Merge pull request #38 from Mikunj/fix/duplicate-messages

[Pending] Fix duplicate messages
pull/40/head
sachaaaaa 7 years ago committed by GitHub
commit 19e664bf38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -685,6 +685,10 @@
friendStatus: 'pending', friendStatus: 'pending',
direction: 'incoming', direction: 'incoming',
preKeyBundle: null, preKeyBundle: null,
timestamp: null,
source: null,
sourceDevice: null,
received_at: null,
...options, ...options,
}; };
@ -695,13 +699,13 @@
return; return;
} }
const lastMessage = this.get('timestamp') || Date.now(); const timestamp = _options.timestamp || this.get('timestamp') || Date.now();
window.log.info( window.log.info(
'adding friend request for', 'adding friend request for',
this.ourNumber, this.ourNumber,
this.idForLogging(), this.idForLogging(),
lastMessage timestamp
); );
this.lastMessageStatus = 'sending'; this.lastMessageStatus = 'sending';
@ -731,12 +735,12 @@
} }
// Add the new message // Add the new message
const timestamp = Date.now(); const received_at = _options.received_at || Date.now();
const message = { const message = {
conversationId: this.id, conversationId: this.id,
type: 'friend-request', type: 'friend-request',
sent_at: lastMessage, sent_at: timestamp,
received_at: timestamp, received_at,
unread: 1, unread: 1,
from: this.id, from: this.id,
to: this.ourNumber, to: this.ourNumber,
@ -744,6 +748,8 @@
direction: _options.direction, direction: _options.direction,
body, body,
preKeyBundle: _options.preKeyBundle, preKeyBundle: _options.preKeyBundle,
source: _options.source,
sourceDevice: _options.sourceDevice,
}; };
const id = await window.Signal.Data.saveMessage(message, { const id = await window.Signal.Data.saveMessage(message, {

@ -664,13 +664,14 @@ async function searchConversations(query, { ConversationCollection }) {
} }
// Message // Message
const MESSAGE_PRE_KEYS = ['identityKey', 'preKey', 'signature', 'signedKey'].map(k => `preKeyBundle.${k}`);
async function getMessageCount() { async function getMessageCount() {
return channels.getMessageCount(); return channels.getMessageCount();
} }
async function saveMessage(data, { forceSave, Message } = {}) { async function saveMessage(data, { forceSave, Message } = {}) {
const id = await channels.saveMessage(_cleanData(data), { forceSave }); const updated = keysFromArrayBuffer(MESSAGE_PRE_KEYS, data);
const id = await channels.saveMessage(_cleanData(updated), { forceSave });
Message.refreshExpirationTimer(); Message.refreshExpirationTimer();
return id; return id;
} }
@ -713,7 +714,8 @@ async function saveLegacyMessage(data) {
} }
async function saveMessages(arrayOfMessages, { forceSave } = {}) { async function saveMessages(arrayOfMessages, { forceSave } = {}) {
await channels.saveMessages(_cleanData(arrayOfMessages), { forceSave }); const updated = arrayOfMessages.map(m => keysFromArrayBuffer(MESSAGE_PRE_KEYS, m));
await channels.saveMessages(_cleanData(updated), { forceSave });
} }
async function removeMessage(id, { Message }) { async function removeMessage(id, { Message }) {
@ -738,13 +740,16 @@ async function getMessageById(id, { Message }) {
return null; return null;
} }
return new Message(message); const encoded = keysToArrayBuffer(MESSAGE_PRE_KEYS, message);
return new Message(encoded);
} }
// For testing only // For testing only
async function getAllMessages({ MessageCollection }) { async function getAllMessages({ MessageCollection }) {
const messages = await channels.getAllMessages(); const messages = await channels.getAllMessages();
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
async function getAllMessageIds() { async function getAllMessageIds() {
@ -766,7 +771,9 @@ async function getMessageBySender(
return null; return null;
} }
return new Message(messages[0]); const encoded = keysToArrayBuffer(MESSAGE_PRE_KEYS, messages[0]);
return new Message(encoded);
} }
async function getUnreadByConversation(conversationId, { MessageCollection }) { async function getUnreadByConversation(conversationId, { MessageCollection }) {
@ -784,7 +791,9 @@ async function getMessagesByConversation(
type, type,
}); });
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
async function removeAllMessagesInConversation( async function removeAllMessagesInConversation(
@ -819,22 +828,26 @@ async function removeAllMessagesInConversation(
async function getMessagesBySentAt(sentAt, { MessageCollection }) { async function getMessagesBySentAt(sentAt, { MessageCollection }) {
const messages = await channels.getMessagesBySentAt(sentAt); const messages = await channels.getMessagesBySentAt(sentAt);
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
async function getExpiredMessages({ MessageCollection }) { async function getExpiredMessages({ MessageCollection }) {
const messages = await channels.getExpiredMessages(); const messages = await channels.getExpiredMessages();
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
async function getOutgoingWithoutExpiresAt({ MessageCollection }) { async function getOutgoingWithoutExpiresAt({ MessageCollection }) {
const messages = await channels.getOutgoingWithoutExpiresAt(); const messages = await channels.getOutgoingWithoutExpiresAt();
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
async function getNextExpiringMessage({ MessageCollection }) { async function getNextExpiringMessage({ MessageCollection }) {
const messages = await channels.getNextExpiringMessage(); const messages = await channels.getNextExpiringMessage();
return new MessageCollection(messages); const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m));
return new MessageCollection(encoded);
} }
// Unprocessed // Unprocessed

@ -178,12 +178,13 @@
}); });
} }
}, },
async showFriendRequest({ pubKey, message, preKeyBundle }) { async showFriendRequest({ pubKey, message, preKeyBundle, options }) {
const controller = window.ConversationController; const controller = window.ConversationController;
const conversation = await controller.getOrCreateAndWait(pubKey, 'private'); const conversation = await controller.getOrCreateAndWait(pubKey, 'private');
if (conversation) { if (conversation) {
conversation.addFriendRequest(message, { conversation.addFriendRequest(message, {
preKeyBundle: preKeyBundle || null, preKeyBundle: preKeyBundle || null,
...options,
}); });
} }
}, },

@ -934,11 +934,17 @@ MessageReceiver.prototype.extend({
return this.innerHandleContentMessage(envelope, plaintext); return this.innerHandleContentMessage(envelope, plaintext);
}); });
}, },
promptUserToAcceptFriendRequest(pubKey, message, preKeyBundle) { promptUserToAcceptFriendRequest(envelope, message, preKeyBundleMessage) {
window.Whisper.events.trigger('showFriendRequest', { window.Whisper.events.trigger('showFriendRequest', {
pubKey, pubKey: envelope.source,
message, message,
preKeyBundle, preKeyBundle: this.decodePreKeyBundleMessage(preKeyBundleMessage),
options: {
source: envelope.source,
sourceDevice: envelope.sourceDevice,
timestamp: envelope.timestamp.toNumber(),
receivedAt: envelope.receivedAt,
},
}); });
}, },
// A handler function for when a friend request is accepted or declined // A handler function for when a friend request is accepted or declined
@ -973,52 +979,49 @@ MessageReceiver.prototype.extend({
const content = textsecure.protobuf.Content.decode(plaintext); const content = textsecure.protobuf.Content.decode(plaintext);
if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) {
// only prompt friend request if there is no conversation yet
let conversation; let conversation;
try { try {
conversation = ConversationController.get(envelope.source); conversation = ConversationController.get(envelope.source);
} catch (e) { } } catch (e) { }
// only prompt friend request if there is no conversation yet
if (!conversation) { if (!conversation) {
this.promptUserToAcceptFriendRequest( this.promptUserToAcceptFriendRequest(
envelope.source, envelope,
content.dataMessage.body, content.dataMessage.body,
content.preKeyBundle, content.preKeyBundleMessage,
); );
return; } else {
} const keyExchangeComplete = conversation.isKeyExchangeCompleted();
}
// Check here if we received preKeys from the other user
// Check if our friend request got accepted // We are certain that other user accepted the friend request IF:
if (content.preKeyBundle) { // - The message has a preKeyBundleMessage
// By default we don't want to save the preKey // - We have an outgoing friend request that is pending
let savePreKey = false; // The second check is crucial because it makes sure we don't save the preKeys of the incoming friend request (which is saved only when we press accept)
if (!keyExchangeComplete && content.preKeyBundleMessage) {
// The conversation // Check for any outgoing friend requests
let conversation = null; const pending = await conversation.getPendingFriendRequests('outgoing');
const successful = pending.filter(p => !p.hasErrors());
try {
conversation = ConversationController.get(envelope.source); // Save the key only if we have an outgoing friend request
const savePreKey = (successful.length > 0);
// We only want to save the preKey if we have a outgoing friend request which is pending
const pending = await conversation.getPendingFriendRequests('outgoing'); // Save the pre key
const successful = pending.filter(p => !p.hasErrors()); if (savePreKey) {
await this.handlePreKeyBundleMessage(
// Save the key only if we have an outgoing friend request envelope.source,
savePreKey = (successful.length > 0); this.decodePreKeyBundleMessage(content.preKeyBundleMessage),
} catch (e) {} );
// Save the pre key if we have a conversation
if (savePreKey && conversation) {
await this.handlePreKeyBundleMessage(
envelope.source,
content.preKeyBundle
);
// Update the conversation
await conversation.onFriendRequestAccepted();
return; // Update the conversation
await conversation.onFriendRequestAccepted();
}
}
} }
// Exit early since the friend request reply will be a regular empty message
return;
} }
if (content.syncMessage) { if (content.syncMessage) {
@ -1235,8 +1238,7 @@ MessageReceiver.prototype.extend({
return this.removeFromCache(envelope); return this.removeFromCache(envelope);
}, },
async handlePreKeyBundleMessage(pubKey, preKeyBundleMessage) { decodePreKeyBundleMessage(preKeyBundleMessage) {
const { preKeyId, signedKeyId } = preKeyBundleMessage;
const [identityKey, preKey, signedKey, signature] = [ const [identityKey, preKey, signedKey, signature] = [
preKeyBundleMessage.identityKey, preKeyBundleMessage.identityKey,
preKeyBundleMessage.preKey, preKeyBundleMessage.preKey,
@ -1244,6 +1246,24 @@ MessageReceiver.prototype.extend({
preKeyBundleMessage.signature, preKeyBundleMessage.signature,
].map(k => dcodeIO.ByteBuffer.wrap(k).toArrayBuffer()); ].map(k => dcodeIO.ByteBuffer.wrap(k).toArrayBuffer());
return {
...preKeyBundleMessage,
identityKey,
preKey,
signedKey,
signature,
};
},
async handlePreKeyBundleMessage(pubKey, preKeyBundleMessage) {
const {
preKeyId,
signedKeyId,
identityKey,
preKey,
signedKey,
signature,
} = preKeyBundleMessage;
if (pubKey != StringView.arrayBufferToHex(identityKey)) { if (pubKey != StringView.arrayBufferToHex(identityKey)) {
throw new Error( throw new Error(
'Error in handlePreKeyBundleMessage: envelope pubkey does not match pubkey in prekey bundle' 'Error in handlePreKeyBundleMessage: envelope pubkey does not match pubkey in prekey bundle'

Loading…
Cancel
Save