From c419ff9cd25ad4cca559297b92e20331874507dc Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 29 Jun 2020 15:37:27 +1000 Subject: [PATCH 01/17] include display name in outgoing messages --- js/models/conversations.js | 26 +++++++++++++++++++ .../outgoing/content/data/ChatMessage.ts | 3 +++ 2 files changed, 29 insertions(+) diff --git a/js/models/conversations.js b/js/models/conversations.js index 6e3dbd861..ea432f57a 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1305,6 +1305,7 @@ }); // FIXME audric add back profileKey + const lokiProfile = this.getOurProfile(); const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ body: messageBody, timestamp: Date.now(), @@ -1312,6 +1313,7 @@ expireTimer, preview, quote, + lokiProfile, }); // Start handle ChatMessages (attachments/quote/preview/body) // FIXME AUDRIC handle attachments, quote, preview, profileKey @@ -2554,6 +2556,30 @@ return this.getNumber(); }, + /** + * Returns + * displayName: string; + * avatarPointer: string; + * profileKey: Uint8Array; + */ + getOurProfile() { + try { + // Secondary devices have their profile stored + // in their primary device's conversation + const ourNumber = window.storage.get('primaryDevicePubKey'); + const ourConversation = window.ConversationController.get(ourNumber); + let profileKey = null; + if (this.get('profileSharing')) { + profileKey = storage.get('profileKey'); + } + const avatarPointer = ourConversation.get('avatarPointer'); + const { displayName } = ourConversation.getLokiProfile(); + return { displayName, avatarPointer, profileKey }; + } catch (e) { + window.log.error(`Failed to get our profile: ${e}`); + return null; + } + }, getNumber() { if (!this.isPrivate()) { diff --git a/ts/session/messages/outgoing/content/data/ChatMessage.ts b/ts/session/messages/outgoing/content/data/ChatMessage.ts index a82cdb37a..2ac442a3d 100644 --- a/ts/session/messages/outgoing/content/data/ChatMessage.ts +++ b/ts/session/messages/outgoing/content/data/ChatMessage.ts @@ -107,6 +107,9 @@ export class ChatMessage extends DataMessage { } if (this.profileKey) { dataMessage.profileKey = this.profileKey; + dataMessage.flags = + // tslint:disable-next-line: no-bitwise + dataMessage.flags | SignalService.DataMessage.Flags.PROFILE_KEY_UPDATE; } if (this.quote) { From 6a91d44e08acf10a4d55867842171dc8768f50ca Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 30 Jun 2020 16:58:28 +1000 Subject: [PATCH 02/17] pass the db id to our messagesender message and clean a few files --- js/models/conversations.js | 19 ++++-- js/models/messages.js | 103 ++++-------------------------- js/views/inbox_view.js | 3 +- libtextsecure/errors.js | 20 ------ libtextsecure/outgoing_message.js | 16 +---- 5 files changed, 30 insertions(+), 131 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index ea432f57a..8e39c9b98 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1267,6 +1267,7 @@ Message: Whisper.Message, }); message.set({ id }); + message.markPendingSend(); this.set({ lastMessage: model.getNotificationText(), @@ -1307,6 +1308,7 @@ // FIXME audric add back profileKey const lokiProfile = this.getOurProfile(); const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ + identifier: id, body: messageBody, timestamp: Date.now(), attachments: finalAttachments, @@ -1322,10 +1324,7 @@ await message.markMessageSyncOnly(); // sending is done in the 'private' case below } - const options = {}; - options.messageType = message.get('type'); - options.isPublic = this.isPublic(); if (this.isPublic()) { // FIXME audric add back attachments, quote, preview const openGroup = { @@ -1334,6 +1333,7 @@ conversationId: this.id, }; const openGroupParams = { + identifier: id, body, timestamp: Date.now(), group: openGroup, @@ -1346,7 +1346,6 @@ return null; } - options.sessionRestoration = sessionRestoration; const destinationPubkey = new libsession.Types.PubKey(destination); // Handle Group Invitation Message if (groupInvitation) { @@ -1358,6 +1357,8 @@ const groupInvitMessage = new libsession.Messages.Outgoing.GroupInvitationMessage( { + identifier: id, + timestamp: Date.now(), serverName: groupInvitation.name, channelId: groupInvitation.channelId, serverAddress: groupInvitation.address, @@ -1379,6 +1380,8 @@ if (this.isMediumGroup()) { const mediumGroupChatMessage = new libsession.Messages.Outgoing.MediumGroupChatMessage( { + identifier: id, + timestamp: chatMessage.timestamp, chatMessage, groupId: destination, } @@ -1395,7 +1398,9 @@ } else { const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( { + identifier: id, chatMessage, + timestamp: chatMessage.timestamp, groupId: destination, } ); @@ -1642,6 +1647,7 @@ } const expireUpdate = { + identifier: id, timestamp: message.get('sent_at'), expireTimer, profileKey, @@ -1822,6 +1828,7 @@ const createParams = { timestamp: Date.now(), groupId: id, + identifier: messageId, groupSecretKey: secretKey, members: members.map(pkHex => StringView.hexToArrayBuffer(pkHex)), groupName: name, @@ -1833,7 +1840,7 @@ const mediumGroupCreateMessage = new libsession.Messages.Outgoing.MediumGroupCreateMessage( createParams ); - message.trigger('pending'); + message.markPendingSend(); members.forEach(member => { const memberPubKey = new libsession.Types.PubKey(member); @@ -1847,6 +1854,7 @@ const updateParams = { timestamp: Date.now(), + identifier: messageId, groupId: this.id, name: this.get('name'), avatar: this.get('avatar'), @@ -1922,6 +1930,7 @@ const quitGroup = { timestamp: Date.now(), groupId: this.id, + identifier: id, }; const quitGroupMessage = new libsession.Messages.Outgoing.ClosedGroupLeaveMessage( quitGroup diff --git a/js/models/messages.js b/js/models/messages.js index 36787bd7f..01d7bc8cc 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -991,6 +991,10 @@ }); }, + markPendingSend() { + this.trigger('pending'); // I don't this does anything + }, + // One caller today: event handler for the 'Retry Send' entry in triple-dot menu async retrySend() { if (!textsecure.messaging) { @@ -1039,12 +1043,13 @@ // const previewWithData = await loadPreviewData(this.get('preview')); const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ body, + identifier: this.id, timestamp: this.get('sent_at'), expireTimer: this.get('expireTimer'), }); // Special-case the self-send case - we send only a sync message if (recipients.length === 1 && recipients[0] === this.OUR_NUMBER) { - this.trigger('pending'); + this.markPendingSend(); // FIXME audric add back profileKey await this.markMessageSyncOnly(); // sending is done in the private case below @@ -1053,19 +1058,20 @@ if (conversation.isPrivate()) { const [number] = recipients; const recipientPubKey = new libsession.Types.PubKey(number); - this.trigger('pending'); + this.markPendingSend(); return libsession .getMessageQueue() .sendUsingMultiDevice(recipientPubKey, chatMessage); } - this.trigger('pending'); + this.markPendingSend(); // TODO should we handle open groups message here too? and mediumgroups // Not sure there is the concept of retrySend for those const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( { chatMessage, + identifier: this.id, groupId: this.get('conversationId'), } ); @@ -1126,7 +1132,7 @@ // Special-case the self-send case - we send only a sync message if (number === this.OUR_NUMBER) { - this.trigger('pending'); + this.markPendingSend(); await this.markMessageSyncOnly(); // sending is done in the private case below } @@ -1134,7 +1140,7 @@ const recipientPubKey = new libsession.Types.PubKey(number); if (conversation.isPrivate()) { - this.trigger('pending'); + this.markPendingSend(); return libsession .getMessageQueue() .sendUsingMultiDevice(recipientPubKey, chatMessage); @@ -1147,7 +1153,7 @@ } ); // resend tries to send the message to that specific user only in the context of a closed group - this.trigger('pending'); + this.markPendingSend(); return libsession .getMessageQueue() .sendUsingMultiDevice(recipientPubKey, closedGroupChatMessage); @@ -1286,92 +1292,7 @@ Message: Whisper.Message, }); }, - send(promise) { - this.trigger('pending'); - return promise - .then(async result => { - this.trigger('done'); - - // This is used by sendSyncMessage, then set to null - if (!this.get('synced') && result.dataMessage) { - this.set({ dataMessage: result.dataMessage }); - } - - const sentTo = this.get('sent_to') || []; - this.set({ - sent_to: _.union(sentTo, result.successfulNumbers), - sent: true, - expirationStartTimestamp: Date.now(), - unidentifiedDeliveries: result.unidentifiedDeliveries, - }); - - await window.Signal.Data.saveMessage(this.attributes, { - Message: Whisper.Message, - }); - - this.trigger('sent', this); - }) - .catch(result => { - this.trigger('done'); - if (result.dataMessage) { - this.set({ dataMessage: result.dataMessage }); - } - - let promises = []; - - if (result instanceof Error) { - this.saveErrors(result); - if (result.name === 'SignedPreKeyRotationError') { - promises.push(getAccountManager().rotateSignedPreKey()); - } else if (result.name === 'OutgoingIdentityKeyError') { - const c = ConversationController.get(result.number); - promises.push(c.getProfiles()); - } - } else { - if (result.successfulNumbers.length > 0) { - const sentTo = this.get('sent_to') || []; - - // In groups, we don't treat unregistered users as a user-visible - // error. The message will look successful, but the details - // screen will show that we didn't send to these unregistered users. - const filteredErrors = _.reject( - result.errors, - error => error.name === 'UnregisteredUserError' - ); - - // We don't start the expiration timer if there are real errors - // left after filtering out all of the unregistered user errors. - const expirationStartTimestamp = filteredErrors.length - ? null - : Date.now(); - - this.saveErrors(filteredErrors); - - this.set({ - sent_to: _.union(sentTo, result.successfulNumbers), - sent: true, - expirationStartTimestamp, - unidentifiedDeliveries: result.unidentifiedDeliveries, - }); - } else { - this.saveErrors(result.errors); - } - promises = promises.concat( - _.map(result.errors, error => { - if (error.name === 'OutgoingIdentityKeyError') { - const c = ConversationController.get(error.number); - promises.push(c.getProfiles()); - } - }) - ); - } - - this.trigger('send-error', this.get('errors')); - - return Promise.all(promises); - }); - }, someRecipientsFailed() { const c = this.getConversation(); diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index d57b6a824..df4be9b87 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -9,7 +9,8 @@ i18n, Whisper, textsecure, - Signal + Signal, + _ */ // eslint-disable-next-line func-names diff --git a/libtextsecure/errors.js b/libtextsecure/errors.js index 70ec36d5b..fca487f0a 100644 --- a/libtextsecure/errors.js +++ b/libtextsecure/errors.js @@ -108,25 +108,6 @@ } inherit(ReplayableError, MessageError); - function UnregisteredUserError(number, httpError) { - this.message = httpError.message; - this.name = 'UnregisteredUserError'; - - Error.call(this, this.message); - - // Maintains proper stack trace, where our error was thrown (only available on V8) - // via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error - if (Error.captureStackTrace) { - Error.captureStackTrace(this); - } - - this.number = number; - this.code = httpError.code; - - appendStack(this, httpError); - } - inherit(Error, UnregisteredUserError); - function EmptySwarmError(number, message) { // eslint-disable-next-line prefer-destructuring this.number = number.split('.')[0]; @@ -276,7 +257,6 @@ } } - window.textsecure.UnregisteredUserError = UnregisteredUserError; window.textsecure.SendMessageNetworkError = SendMessageNetworkError; window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError; diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 68e2466b0..685e2e0c2 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -281,14 +281,7 @@ OutgoingMessage.prototype = { }).then(results => results.every(value => value === true)); }) .catch(e => { - if (e.name === 'HTTPError' && e.code === 404) { - if (device !== 1) { - return this.removeDeviceIdsForNumber(number, [device]); - } - throw new textsecure.UnregisteredUserError(number, e); - } else { - throw e; - } + throw e; }) ); }); @@ -312,12 +305,7 @@ OutgoingMessage.prototype = { await lokiMessageAPI.sendMessage(pubKey, data, timestamp, ttl, options); } catch (e) { if (e.name === 'HTTPError' && e.code !== 409 && e.code !== 410) { - // 409 and 410 should bubble and be handled by doSendMessage - // 404 should throw UnregisteredUserError - // all other network errors can be retried later. - if (e.code === 404) { - throw new textsecure.UnregisteredUserError(number, e); - } + throw new textsecure.SendMessageNetworkError(number, '', e, timestamp); } else if (e.name === 'TimedOutError') { throw new textsecure.PoWError(number, e); From 8e0a46699677b91e180167f99ea31f1e4cdb1500 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 30 Jun 2020 16:58:53 +1000 Subject: [PATCH 03/17] basic message sending event handling --- js/views/inbox_view.js | 106 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index df4be9b87..7ebf4ad8f 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -244,6 +244,9 @@ // } // } // }); + this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(this); + this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this); + this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this); this.listenTo(convoCollection, 'remove', conversation => { const { id } = conversation || {}; @@ -259,12 +262,115 @@ }); this.listenTo(convoCollection, 'reset', removeAllConversations); + + window.libsession.getMessageQueue().events.addListener('success', this.handleMessageSentSuccess); + + + window.libsession.getMessageQueue().events.addListener('fail', this.handleMessageSentFailure); + Whisper.events.on('messageExpired', messageExpired); Whisper.events.on('userChanged', userChanged); // Finally, add it to the DOM this.$('.left-pane-placeholder').append(this.leftPaneView.el); }, + + async fetchHandleMessageSentData(m) { + // nobody is listening to this freshly fetched message .trigger calls + const tmpMsg = await window.Signal.Data.getMessageById(m.identifier, { + Message: Whisper.Message, + }); + + if (!tmpMsg) { + return null; + } + + // find the corresponding conversation of this message + const conv = window.ConversationController.get(tmpMsg.get('conversationId')); + + // then, find in this conversation the very same message + const msg = conv.messageCollection.models.find( + convMsg => convMsg.id === tmpMsg.id + ); + return { conv, msg }; + }, + + async handleMessageSentSuccess(m) { + const fetchedData = await this.fetchHandleMessageSentData(m); + if (!fetchedData) { + return; + } + const { msg, conv } = fetchedData; + + const sentTo = msg.get('sent_to') || []; + + const isOurDevice = window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( + m.device + ); + + // Handle the sync logic here + if (!isOurDevice && !msg.get('synced') && !msg.get('sentSync')) { + // FIXME audric send the syncMessage + // const contentDecoded = textsecure.protobuf.Content.decode(m.plainTextBuffer); + // const { dataMessage } = contentDecoded; + + msg.set({ sentSync: true }); + } else if (isOurDevice && msg.get('sentSync')) { + msg.set({ synced: true }); + } + + msg.set({ + sent_to: _.union(sentTo, m.device), + sent: true, + expirationStartTimestamp: Date.now(), + // unidentifiedDeliveries: result.unidentifiedDeliveries, + }); + + await window.Signal.Data.saveMessage(msg.attributes, { + Message: Whisper.Message, + }); + conv.updateLastMessage(); + + msg.trigger('sent', msg); + }, + + async handleMessageSentFailure(m, error) { + const fetchedData = await this.fetchHandleMessageSentData(m); + if (!fetchedData) { + return; + } + const { msg, conv } = fetchedData; + if (error instanceof Error) { + msg.saveErrors(error); + if (error.name === 'SignedPreKeyRotationError') { + await window.getAccountManager().rotateSignedPreKey(); + } else if (error.name === 'OutgoingIdentityKeyError') { + const c = ConversationController.get(m.device); + await c.getProfiles(); + } + } + // if (result.successfulNumbers.length > 0) { + // const sentTo = this.get('sent_to') || []; + + const expirationStartTimestamp = Date.now(); + if (m.device === window.textsecure.storage.user.getNumber() && !msg.get('sync')) { + msg.set({ sentSync: false }); + } + msg.set({ + // sent_to: _.union(sentTo, m.device), + sent: true, + expirationStartTimestamp, + // unidentifiedDeliveries: result.unidentifiedDeliveries, + }); + await window.Signal.Data.saveMessage(msg.attributes, { + Message: Whisper.Message, + }); + msg.trigger('change', msg); + + conv.updateLastMessage(); + msg.trigger('done'); + }, + startConnectionListener() { this.interval = setInterval(() => { const status = window.getSocketStatus(); From fb7e13acb080c787d635148fb9d95a1966dec5a7 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 30 Jun 2020 17:07:32 +1000 Subject: [PATCH 04/17] lint --- js/models/messages.js | 1 - js/views/inbox_view.js | 23 ++++++++++++++++------- libtextsecure/outgoing_message.js | 1 - 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/js/models/messages.js b/js/models/messages.js index 01d7bc8cc..0e41b7e26 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1293,7 +1293,6 @@ }); }, - someRecipientsFailed() { const c = this.getConversation(); if (!c || c.isPrivate()) { diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index 7ebf4ad8f..fed468cf7 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -244,7 +244,9 @@ // } // } // }); - this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(this); + this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind( + this + ); this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this); this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this); @@ -262,11 +264,13 @@ }); this.listenTo(convoCollection, 'reset', removeAllConversations); + window.libsession + .getMessageQueue() + .events.addListener('success', this.handleMessageSentSuccess); - window.libsession.getMessageQueue().events.addListener('success', this.handleMessageSentSuccess); - - - window.libsession.getMessageQueue().events.addListener('fail', this.handleMessageSentFailure); + window.libsession + .getMessageQueue() + .events.addListener('fail', this.handleMessageSentFailure); Whisper.events.on('messageExpired', messageExpired); Whisper.events.on('userChanged', userChanged); @@ -286,7 +290,9 @@ } // find the corresponding conversation of this message - const conv = window.ConversationController.get(tmpMsg.get('conversationId')); + const conv = window.ConversationController.get( + tmpMsg.get('conversationId') + ); // then, find in this conversation the very same message const msg = conv.messageCollection.models.find( @@ -353,7 +359,10 @@ // const sentTo = this.get('sent_to') || []; const expirationStartTimestamp = Date.now(); - if (m.device === window.textsecure.storage.user.getNumber() && !msg.get('sync')) { + if ( + m.device === window.textsecure.storage.user.getNumber() && + !msg.get('sync') + ) { msg.set({ sentSync: false }); } msg.set({ diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 685e2e0c2..3ef1c3799 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -305,7 +305,6 @@ OutgoingMessage.prototype = { await lokiMessageAPI.sendMessage(pubKey, data, timestamp, ttl, options); } catch (e) { if (e.name === 'HTTPError' && e.code !== 409 && e.code !== 410) { - throw new textsecure.SendMessageNetworkError(number, '', e, timestamp); } else if (e.name === 'TimedOutError') { throw new textsecure.PoWError(number, e); From 4c890482f7f75aa038db4672bdcadbce60e105ef Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 1 Jul 2020 10:44:59 +1000 Subject: [PATCH 05/17] handle sending events on messages (sent/error) --- js/models/messages.js | 8 +++++--- js/views/inbox_view.js | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/js/models/messages.js b/js/models/messages.js index 0e41b7e26..f98076e3f 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -5,7 +5,6 @@ filesize, ConversationController, MessageController, - getAccountManager, i18n, Signal, textsecure, @@ -1003,7 +1002,9 @@ } this.set({ errors: null }); - + await window.Signal.Data.saveMessage(this.attributes, { + Message: Whisper.Message, + }); const conversation = this.getConversation(); const intendedRecipients = this.get('recipients') || []; const successfulRecipients = this.get('sent_to') || []; @@ -1014,7 +1015,7 @@ // : null; let recipients = _.intersection(intendedRecipients, currentRecipients); - recipients = _.without(recipients, successfulRecipients); + recipients = recipients.filter(key => !successfulRecipients.includes(key)); if (!recipients.length) { window.log.warn('retrySend: Nobody to send to!'); @@ -1032,6 +1033,7 @@ attachments: attachmentsWithData, now: this.get('sent_at'), }); + // TODO add logic for attachments, quote and preview here // don't blindly reuse the one from loadQuoteData loadPreviewData and getLongMessageAttachment. // they have similar data structure to the ones we need diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index fed468cf7..fbd22e6e7 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -326,7 +326,7 @@ } msg.set({ - sent_to: _.union(sentTo, m.device), + sent_to: _.union(sentTo, [m.device]), sent: true, expirationStartTimestamp: Date.now(), // unidentifiedDeliveries: result.unidentifiedDeliveries, @@ -366,7 +366,6 @@ msg.set({ sentSync: false }); } msg.set({ - // sent_to: _.union(sentTo, m.device), sent: true, expirationStartTimestamp, // unidentifiedDeliveries: result.unidentifiedDeliveries, From 2a3b82ed9ca10bca4beb4ce08318548509061e1b Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 1 Jul 2020 10:45:17 +1000 Subject: [PATCH 06/17] retrySend: handle public groups --- js/models/messages.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/js/models/messages.js b/js/models/messages.js index f98076e3f..70b5fb5da 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1014,8 +1014,28 @@ // ? storage.get('profileKey') // : null; + if (conversation.isPublic()) { + const openGroup = { + server: conversation.get('server'), + channel: conversation.get('channelId'), + conversationId: conversation.id, + }; + const openGroupParams = { + identifier: this.id, + body: this.get('body'), + timestamp: Date.now(), + group: openGroup, + }; + const openGroupMessage = new libsession.Messages.Outgoing.OpenGroupMessage( + openGroupParams + ); + return libsession.getMessageQueue().sendToGroup(openGroupMessage); + } + let recipients = _.intersection(intendedRecipients, currentRecipients); - recipients = recipients.filter(key => !successfulRecipients.includes(key)); + recipients = recipients.filter( + key => !successfulRecipients.includes(key) + ); if (!recipients.length) { window.log.warn('retrySend: Nobody to send to!'); From 1201707d17cc0a31e6bb2d34c7e75f80df055b86 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 1 Jul 2020 11:31:10 +1000 Subject: [PATCH 07/17] show tiny wheel while message is in sending state --- ts/components/conversation/Message.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 98b43c557..59f57566f 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -266,6 +266,14 @@ export class Message extends React.PureComponent { const isShowingImage = this.isShowingImage(); const withImageNoCaption = Boolean(!text && isShowingImage); const showError = status === 'error' && direction === 'outgoing'; + const showSentNoErrors = + !textPending && + direction === 'outgoing' && + status !== 'error' && + status !== 'sending'; + + const showSending = + !textPending && direction === 'outgoing' && status === 'sending'; return (
{
) : null} - {!textPending && direction === 'outgoing' && status !== 'error' ? ( + {showSending ? ( +
+ ) : null} + {showSentNoErrors ? (
Date: Wed, 1 Jul 2020 11:55:51 +1000 Subject: [PATCH 08/17] send sync message when a message was sent to someone --- js/models/conversations.js | 2 -- js/models/messages.js | 5 ----- js/views/inbox_view.js | 17 ++++++++++------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 09e8b90f1..191562d62 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1279,7 +1279,6 @@ Message: Whisper.Message, }); message.set({ id }); - message.markPendingSend(); this.set({ lastMessage: model.getNotificationText(), @@ -1840,7 +1839,6 @@ const mediumGroupCreateMessage = new libsession.Messages.Outgoing.MediumGroupCreateMessage( createParams ); - message.markPendingSend(); members.forEach(member => { const memberPubKey = new libsession.Types.PubKey(member); diff --git a/js/models/messages.js b/js/models/messages.js index fa7213dee..752efb77c 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1098,7 +1098,6 @@ // Special-case the self-send case - we send only a sync message if (recipients.length === 1 && recipients[0] === this.OUR_NUMBER) { - this.trigger('pending'); // FIXME audric add back profileKey return this.sendSyncMessageOnly(chatMessage); } @@ -1106,14 +1105,12 @@ if (conversation.isPrivate()) { const [number] = recipients; const recipientPubKey = new libsession.Types.PubKey(number); - this.trigger('pending'); return libsession .getMessageQueue() .sendUsingMultiDevice(recipientPubKey, chatMessage); } - this.trigger('pending'); // TODO should we handle medium groups message here too? // Not sure there is the concept of retrySend for those const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( @@ -1173,8 +1170,6 @@ quote, }); - this.trigger('pending'); - // Special-case the self-send case - we send only a sync message if (number === this.OUR_NUMBER) { return this.sendSyncMessageOnly(chatMessage); diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index fbd22e6e7..96a343342 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -10,6 +10,7 @@ Whisper, textsecure, Signal, + libsession, _ */ @@ -316,17 +317,21 @@ // Handle the sync logic here if (!isOurDevice && !msg.get('synced') && !msg.get('sentSync')) { - // FIXME audric send the syncMessage - // const contentDecoded = textsecure.protobuf.Content.decode(m.plainTextBuffer); - // const { dataMessage } = contentDecoded; + const contentDecoded = textsecure.protobuf.Content.decode( + m.plainTextBuffer + ); + const { dataMessage } = contentDecoded; + msg.sendSyncMessageOnly(dataMessage); msg.set({ sentSync: true }); } else if (isOurDevice && msg.get('sentSync')) { msg.set({ synced: true }); } - + const primaryPubKey = await libsession.Protocols.MultiDeviceProtocol.getPrimaryDevice( + m.device + ); msg.set({ - sent_to: _.union(sentTo, [m.device]), + sent_to: _.union(sentTo, [primaryPubKey.key]), sent: true, expirationStartTimestamp: Date.now(), // unidentifiedDeliveries: result.unidentifiedDeliveries, @@ -355,8 +360,6 @@ await c.getProfiles(); } } - // if (result.successfulNumbers.length > 0) { - // const sentTo = this.get('sent_to') || []; const expirationStartTimestamp = Date.now(); if ( From 847db5b43aa1955aa64f793fb4333699f9dba799 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 1 Jul 2020 13:14:55 +1000 Subject: [PATCH 09/17] fix typo --- js/modules/data.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/modules/data.d.ts b/js/modules/data.d.ts index f95dd8a6e..ff674c588 100644 --- a/js/modules/data.d.ts +++ b/js/modules/data.d.ts @@ -1,5 +1,5 @@ import { ConversationType } from '../../ts/state/ducks/conversations'; -import { Mesasge } from '../../ts/types/Message'; +import { Message } from '../../ts/types/Message'; type IdentityKey = { id: string; @@ -223,7 +223,7 @@ export function searchMessagesInConversation( ): Promise; export function getMessageCount(): Promise; export function saveMessage( - data: Mesasge, + data: Message, { forceSave, Message }?: { forceSave: any; Message: any } ): Promise; export function cleanSeenMessages(): Promise; From f3ae798b1263cf985bb8511417b3789dab0b1c23 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 09:46:55 +1000 Subject: [PATCH 10/17] remove SESSION_REQUEST flag from DataMessage. now in envelope --- protos/SignalService.proto | 1 - ts/receiver/receiver.ts | 3 --- 2 files changed, 4 deletions(-) diff --git a/protos/SignalService.proto b/protos/SignalService.proto index 69be6de73..0a5300c5d 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -142,7 +142,6 @@ message DataMessage { PROFILE_KEY_UPDATE = 4; SESSION_RESTORE = 64; UNPAIRING_REQUEST = 128; - SESSION_REQUEST = 256; } message Quote { diff --git a/ts/receiver/receiver.ts b/ts/receiver/receiver.ts index 4c34efaf9..8991e53c4 100644 --- a/ts/receiver/receiver.ts +++ b/ts/receiver/receiver.ts @@ -344,8 +344,6 @@ export function processDecrypted(envelope: EnvelopePlus, decrypted: any) { } else if (decrypted.flags & FLAGS.PROFILE_KEY_UPDATE) { decrypted.body = ''; decrypted.attachments = []; - } else if (decrypted.flags & FLAGS.SESSION_REQUEST) { - // do nothing } else if (decrypted.flags & FLAGS.SESSION_RESTORE) { // do nothing } else if (decrypted.flags & FLAGS.UNPAIRING_REQUEST) { @@ -569,7 +567,6 @@ export async function handleMessageEvent(event: any): Promise { const { PROFILE_KEY_UPDATE, - SESSION_REQUEST, SESSION_RESTORE, } = SignalService.DataMessage.Flags; From 0474e84b19a982f4e483ddd91733eea6906c484a Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 09:49:12 +1000 Subject: [PATCH 11/17] fix profileKey sharing and avatar --- js/models/conversations.js | 1 + js/models/messages.js | 1 + .../messages/outgoing/content/data/ChatMessage.ts | 15 +++++++-------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 191562d62..c592d8489 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1315,6 +1315,7 @@ expireTimer, preview: uploads.preview, quote: uploads.quote, + lokiProfile: this.getOurProfile(), }); if (this.isMe()) { diff --git a/js/models/messages.js b/js/models/messages.js index 752efb77c..ea04cd15e 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1094,6 +1094,7 @@ attachments, preview, quote, + lokiProfile: this.getOurProfile(), }); // Special-case the self-send case - we send only a sync message diff --git a/ts/session/messages/outgoing/content/data/ChatMessage.ts b/ts/session/messages/outgoing/content/data/ChatMessage.ts index 47c63b1f7..0ad70faa8 100644 --- a/ts/session/messages/outgoing/content/data/ChatMessage.ts +++ b/ts/session/messages/outgoing/content/data/ChatMessage.ts @@ -2,6 +2,7 @@ import { DataMessage } from './DataMessage'; import { SignalService } from '../../../../../protobuf'; import { MessageParams } from '../../Message'; import { LokiProfile } from '../../../../../types/Message'; +import ByteBuffer from 'bytebuffer'; export interface AttachmentPointer { id?: number; @@ -62,7 +63,12 @@ export class ChatMessage extends DataMessage { this.body = params.body; this.quote = params.quote; this.expireTimer = params.expireTimer; - this.profileKey = params.lokiProfile && params.lokiProfile.profileKey; + if (params.lokiProfile && params.lokiProfile.profileKey) { + this.profileKey = new Uint8Array( + ByteBuffer.wrap(params.lokiProfile.profileKey).toArrayBuffer() + ); + } + this.displayName = params.lokiProfile && params.lokiProfile.displayName; this.avatarPointer = params.lokiProfile && params.lokiProfile.avatarPointer; this.preview = params.preview; @@ -85,10 +91,6 @@ export class ChatMessage extends DataMessage { dataMessage.expireTimer = this.expireTimer; } - if (this.profileKey) { - dataMessage.profileKey = this.profileKey; - } - if (this.preview) { dataMessage.preview = this.preview; } @@ -107,9 +109,6 @@ export class ChatMessage extends DataMessage { } if (this.profileKey) { dataMessage.profileKey = this.profileKey; - dataMessage.flags = - // tslint:disable-next-line: no-bitwise - dataMessage.flags | SignalService.DataMessage.Flags.PROFILE_KEY_UPDATE; } if (this.quote) { From 1a09ba0b35552e1fce5365291d951cc8a21176bb Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 11:28:04 +1000 Subject: [PATCH 12/17] remove identifier from message to disable syncing of them on events callback --- js/models/conversations.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index c592d8489..3709b809d 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1852,8 +1852,8 @@ } const updateParams = { + // if we do set an identifier here, be sure to not sync the message two times in msg.handleMessageSentSuccess() timestamp: Date.now(), - identifier: messageId, groupId: this.id, name: this.get('name'), avatar: this.get('avatar'), @@ -1926,7 +1926,7 @@ const quitGroup = { timestamp: Date.now(), groupId: this.id, - identifier: id, + // if we do set an identifier here, be sure to not sync it a second time in handleMessageSentSuccess() }; const quitGroupMessage = new libsession.Messages.Outgoing.ClosedGroupLeaveMessage( quitGroup From 5610ec5a9fc3a575da34a665bbbcd0e28930bf69 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 11:29:02 +1000 Subject: [PATCH 13/17] move handling of message event sending to message.js --- js/models/messages.js | 72 ++++++++++++++++++++++++++++++++++++- js/views/inbox_view.js | 80 +++++------------------------------------- 2 files changed, 80 insertions(+), 72 deletions(-) diff --git a/js/models/messages.js b/js/models/messages.js index ea04cd15e..f10665e9f 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -990,7 +990,8 @@ }); }, - /* Uploads attachments, previews and quotes. + /** + * Uploads attachments, previews and quotes. * If body is too long then it is also converted to an attachment. * * @returns The uploaded data which includes: body, attachments, preview and quote. @@ -1215,6 +1216,75 @@ return errors[0][0]; }, + async handleMessageSentSuccess(sentMessage) { + const sentTo = this.get('sent_to') || []; + + const isOurDevice = window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( + sentMessage.device + ); + + // Handle the sync logic here + if (!isOurDevice && !this.get('synced') && !this.get('sentSync')) { + const contentDecoded = textsecure.protobuf.Content.decode( + sentMessage.plainTextBuffer + ); + const { dataMessage } = contentDecoded; + this.sendSyncMessageOnly(dataMessage); + + this.set({ sentSync: true }); + } else if (isOurDevice && this.get('sentSync')) { + this.set({ synced: true }); + } + const primaryPubKey = await libsession.Protocols.MultiDeviceProtocol.getPrimaryDevice( + sentMessage.device + ); + this.set({ + sent_to: _.union(sentTo, [primaryPubKey.key]), + sent: true, + expirationStartTimestamp: Date.now(), + // unidentifiedDeliveries: result.unidentifiedDeliveries, + }); + + await window.Signal.Data.saveMessage(this.attributes, { + Message: Whisper.Message, + }); + this.getConversation().updateLastMessage(); + + this.trigger('sent', this); + }, + + async handleMessageSentFailure(sentMessage, error) { + if (error instanceof Error) { + this.saveErrors(error); + if (error.name === 'SignedPreKeyRotationError') { + await window.getAccountManager().rotateSignedPreKey(); + } else if (error.name === 'OutgoingIdentityKeyError') { + const c = ConversationController.get(sentMessage.device); + await c.getProfiles(); + } + } + + const expirationStartTimestamp = Date.now(); + if ( + sentMessage.device === window.textsecure.storage.user.getNumber() && + !this.get('sync') + ) { + this.set({ sentSync: false }); + } + this.set({ + sent: true, + expirationStartTimestamp, + // unidentifiedDeliveries: result.unidentifiedDeliveries, + }); + await window.Signal.Data.saveMessage(this.attributes, { + Message: Whisper.Message, + }); + this.trigger('change', this); + + this.getConversation().updateLastMessage(); + this.trigger('done'); + }, + getConversation() { // This needs to be an unsafe call, because this method is called during // initial module setup. We may be in the middle of the initial fetch to diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index 96a343342..0e4c89681 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -10,8 +10,6 @@ Whisper, textsecure, Signal, - libsession, - _ */ // eslint-disable-next-line func-names @@ -299,87 +297,27 @@ const msg = conv.messageCollection.models.find( convMsg => convMsg.id === tmpMsg.id ); - return { conv, msg }; + return { msg }; }, - async handleMessageSentSuccess(m) { - const fetchedData = await this.fetchHandleMessageSentData(m); + async handleMessageSentSuccess(sentMessage) { + const fetchedData = await this.fetchHandleMessageSentData(sentMessage); if (!fetchedData) { return; } - const { msg, conv } = fetchedData; + const { msg } = fetchedData; - const sentTo = msg.get('sent_to') || []; - - const isOurDevice = window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( - m.device - ); - - // Handle the sync logic here - if (!isOurDevice && !msg.get('synced') && !msg.get('sentSync')) { - const contentDecoded = textsecure.protobuf.Content.decode( - m.plainTextBuffer - ); - const { dataMessage } = contentDecoded; - msg.sendSyncMessageOnly(dataMessage); - - msg.set({ sentSync: true }); - } else if (isOurDevice && msg.get('sentSync')) { - msg.set({ synced: true }); - } - const primaryPubKey = await libsession.Protocols.MultiDeviceProtocol.getPrimaryDevice( - m.device - ); - msg.set({ - sent_to: _.union(sentTo, [primaryPubKey.key]), - sent: true, - expirationStartTimestamp: Date.now(), - // unidentifiedDeliveries: result.unidentifiedDeliveries, - }); - - await window.Signal.Data.saveMessage(msg.attributes, { - Message: Whisper.Message, - }); - conv.updateLastMessage(); - - msg.trigger('sent', msg); + msg.handleMessageSentSuccess(sentMessage); }, - async handleMessageSentFailure(m, error) { - const fetchedData = await this.fetchHandleMessageSentData(m); + async handleMessageSentFailure(sentMessage, error) { + const fetchedData = await this.fetchHandleMessageSentData(sentMessage); if (!fetchedData) { return; } - const { msg, conv } = fetchedData; - if (error instanceof Error) { - msg.saveErrors(error); - if (error.name === 'SignedPreKeyRotationError') { - await window.getAccountManager().rotateSignedPreKey(); - } else if (error.name === 'OutgoingIdentityKeyError') { - const c = ConversationController.get(m.device); - await c.getProfiles(); - } - } - - const expirationStartTimestamp = Date.now(); - if ( - m.device === window.textsecure.storage.user.getNumber() && - !msg.get('sync') - ) { - msg.set({ sentSync: false }); - } - msg.set({ - sent: true, - expirationStartTimestamp, - // unidentifiedDeliveries: result.unidentifiedDeliveries, - }); - await window.Signal.Data.saveMessage(msg.attributes, { - Message: Whisper.Message, - }); - msg.trigger('change', msg); + const { msg } = fetchedData; - conv.updateLastMessage(); - msg.trigger('done'); + await msg.handleMessageSentFailure(sentMessage, error); }, startConnectionListener() { From 105acd63d86152e99291f044fbd7a0f755855c4c Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 11:48:21 +1000 Subject: [PATCH 14/17] reenable isVerifier on contactCollection --- js/models/conversations.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 3709b809d..5fd752552 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -723,15 +723,13 @@ if (!this.contactCollection.length) { return false; } - // console.log('this.contactCollection', this.contactCollection); - // FIXME AUDRIC - return true; - // return this.contactCollection.every(contact => { - // if (contact.isMe()) { - // return true; - // } - // return contact.isVerified(); - // }); + + return this.contactCollection.every(contact => { + if (contact.isMe()) { + return true; + } + return contact.isVerified(); + }); }, async getPrimaryConversation() { if (!this.isSecondaryDevice()) { From 1413b9874966baac4a57b247e74e12da8205f61e Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 11:48:43 +1000 Subject: [PATCH 15/17] create a conversation with member of a closedgroup we receive --- js/models/conversations.js | 3 ++- libloki/api.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 5fd752552..c77fe06ec 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1839,8 +1839,9 @@ createParams ); - members.forEach(member => { + members.forEach(async member => { const memberPubKey = new libsession.Types.PubKey(member); + await ConversationController.getOrCreateAndWait(member, 'private'); libsession .getMessageQueue() .sendUsingMultiDevice(memberPubKey, mediumGroupCreateMessage); diff --git a/libloki/api.js b/libloki/api.js index 679055724..d187cfb45 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -1,4 +1,4 @@ -/* global window, textsecure, libsession */ +/* global window, textsecure, libsession, ConversationController */ /* eslint-disable no-bitwise */ // eslint-disable-next-line func-names @@ -108,6 +108,7 @@ const ourPubKey = textsecure.storage.user.getNumber(); if (memberStr !== ourPubKey) { const memberPubkey = new libsession.Types.PubKey(memberStr); + await ConversationController.getOrCreateAndWait(memberStr, 'private'); await libsession.Protocols.SessionProtocol.sendSessionRequestIfNeeded( memberPubkey ); From bbebfa4c7e440cd715f8957e792ba6541a2ebe13 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 11:50:31 +1000 Subject: [PATCH 16/17] remove fixed comments --- js/models/conversations.js | 1 - js/models/messages.js | 5 ----- ts/receiver/receiver.ts | 1 + 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index c77fe06ec..2111ffefb 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1304,7 +1304,6 @@ try { const uploads = await message.uploadData(); - // FIXME audric add back profileKey const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ body: uploads.body, identifier: id, diff --git a/js/models/messages.js b/js/models/messages.js index f10665e9f..ed2716f17 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1050,10 +1050,6 @@ const successfulRecipients = this.get('sent_to') || []; const currentRecipients = conversation.getRecipients(); - // const profileKey = conversation.get('profileSharing') - // ? storage.get('profileKey') - // : null; - if (conversation.isPublic()) { const openGroup = { server: conversation.get('server'), @@ -1100,7 +1096,6 @@ // Special-case the self-send case - we send only a sync message if (recipients.length === 1 && recipients[0] === this.OUR_NUMBER) { - // FIXME audric add back profileKey return this.sendSyncMessageOnly(chatMessage); } diff --git a/ts/receiver/receiver.ts b/ts/receiver/receiver.ts index 8991e53c4..0fd2c5592 100644 --- a/ts/receiver/receiver.ts +++ b/ts/receiver/receiver.ts @@ -175,6 +175,7 @@ enum ConversationType { } async function sendDeliveryReceipt(source: string, timestamp: any) { + // FIXME audric // const receiptMessage = new DeliveryReceiptMessage({ // timestamp: Date.now(), // timestamps: [timestamp], From af7f73073b14eee3daa9b24081e6ffac218ed3b9 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 2 Jul 2020 13:58:01 +1000 Subject: [PATCH 17/17] address review --- js/models/conversations.js | 8 +++----- js/models/messages.js | 32 ++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 2111ffefb..d97802536 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1215,11 +1215,6 @@ const expireTimer = this.get('expireTimer'); const recipients = this.getRecipients(); - // let profileKey; - // if (this.get('profileSharing')) { - // profileKey = storage.get('profileKey'); - // } - this.queueJob(async () => { const now = Date.now(); @@ -1329,6 +1324,9 @@ body, timestamp: Date.now(), group: openGroup, + attachments: uploads.attachments, + preview: uploads.preview, + quote: uploads.quote, }; const openGroupMessage = new libsession.Messages.Outgoing.OpenGroupMessage( openGroupParams diff --git a/js/models/messages.js b/js/models/messages.js index ed2716f17..c62ea22fe 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1056,11 +1056,16 @@ channel: conversation.get('channelId'), conversationId: conversation.id, }; + const { body, attachments, preview, quote } = await this.uploadData(); + const openGroupParams = { identifier: this.id, - body: this.get('body'), + body, timestamp: Date.now(), group: openGroup, + attachments, + preview, + quote, }; const openGroupMessage = new libsession.Messages.Outgoing.OpenGroupMessage( openGroupParams @@ -1214,7 +1219,7 @@ async handleMessageSentSuccess(sentMessage) { const sentTo = this.get('sent_to') || []; - const isOurDevice = window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( + const isOurDevice = await window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( sentMessage.device ); @@ -1224,9 +1229,9 @@ sentMessage.plainTextBuffer ); const { dataMessage } = contentDecoded; - this.sendSyncMessageOnly(dataMessage); - - this.set({ sentSync: true }); + if (dataMessage) { + this.sendSyncMessage(dataMessage); + } } else if (isOurDevice && this.get('sentSync')) { this.set({ synced: true }); } @@ -1258,12 +1263,11 @@ await c.getProfiles(); } } - + const isOurDevice = await window.libsession.Protocols.MultiDeviceProtocol.isOurDevice( + sentMessage.device + ); const expirationStartTimestamp = Date.now(); - if ( - sentMessage.device === window.textsecure.storage.user.getNumber() && - !this.get('sync') - ) { + if (isOurDevice && !this.get('sync')) { this.set({ sentSync: false }); } this.set({ @@ -1419,8 +1423,7 @@ }, async sendSyncMessage(dataMessage) { - // TODO: Return here if we've already sent a sync message - if (this.get('synced')) { + if (this.get('synced') || this.get('sentSync')) { return; } @@ -1435,6 +1438,11 @@ }); await libsession.getMessageQueue().sendSyncMessage(syncMessage); + + this.set({ sentSync: true }); + await window.Signal.Data.saveMessage(this.attributes, { + Message: Whisper.Message, + }); }, someRecipientsFailed() {