From cfd76587f60887be2c155ab127e7a7798dd022cb Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Jun 2020 16:12:45 +1000 Subject: [PATCH 01/13] remove getSendOptions and getNumberInfo() --- js/conversation_controller.js | 6 +-- js/models/conversations.js | 72 ----------------------------------- 2 files changed, 2 insertions(+), 76 deletions(-) diff --git a/js/conversation_controller.js b/js/conversation_controller.js index c018f9abc..faa38d844 100644 --- a/js/conversation_controller.js +++ b/js/conversation_controller.js @@ -206,12 +206,10 @@ ); }); }, - prepareForSend(id, options) { + prepareForSend(id) { // id is either a group id or an individual user's id const conversation = this.get(id); - const sendOptions = conversation - ? conversation.getSendOptions(options) - : null; + const sendOptions = {}; const wrap = conversation ? conversation.wrapSend.bind(conversation) : promise => promise; diff --git a/js/models/conversations.js b/js/models/conversations.js index 3f71ae135..a99ccbccc 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1531,78 +1531,6 @@ ); }, - getSendOptions(options = {}) { - const senderCertificate = storage.get('senderCertificate'); - const numberInfo = this.getNumberInfo(options); - - return { - senderCertificate, - numberInfo, - }; - }, - - getNumberInfo(options = {}) { - const { syncMessage, disableMeCheck } = options; - - if (!this.ourNumber) { - return null; - } - - // START: this code has an Expiration date of ~2018/11/21 - // We don't want to enable unidentified delivery for send unless it is - // also enabled for our own account. - const me = ConversationController.getOrCreate(this.ourNumber, 'private'); - if ( - !disableMeCheck && - me.get('sealedSender') === SEALED_SENDER.DISABLED - ) { - return null; - } - // END - - if (!this.isPrivate()) { - const infoArray = this.contactCollection.map(conversation => - conversation.getNumberInfo(options) - ); - return Object.assign({}, ...infoArray); - } - - const accessKey = this.get('accessKey'); - const sealedSender = this.get('sealedSender'); - - // We never send sync messages as sealed sender - if (syncMessage && this.id === this.ourNumber) { - return null; - } - - // If we've never fetched user's profile, we default to what we have - if (sealedSender === SEALED_SENDER.UNKNOWN) { - return { - [this.id]: { - accessKey: - accessKey || - window.Signal.Crypto.arrayBufferToBase64( - window.Signal.Crypto.getRandomBytes(16) - ), - }, - }; - } - - if (sealedSender === SEALED_SENDER.DISABLED) { - return null; - } - - return { - [this.id]: { - accessKey: - accessKey && sealedSender === SEALED_SENDER.ENABLED - ? accessKey - : window.Signal.Crypto.arrayBufferToBase64( - window.Signal.Crypto.getRandomBytes(16) - ), - }, - }; - }, async updateSwarmNodes(swarmNodes) { this.set({ swarmNodes }); await window.Signal.Data.updateConversation(this.id, this.attributes, { From 11c5061dce580aaf549b0e9a991c4662321b0c1f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Jun 2020 16:37:34 +1000 Subject: [PATCH 02/13] update retrySend() and resend() to new pipeline --- js/models/messages.js | 143 ++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 82 deletions(-) diff --git a/js/models/messages.js b/js/models/messages.js index e66d95280..cdb5fa3b4 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1005,9 +1005,9 @@ const successfulRecipients = this.get('sent_to') || []; const currentRecipients = conversation.getRecipients(); - const profileKey = conversation.get('profileSharing') - ? storage.get('profileKey') - : null; + // const profileKey = conversation.get('profileSharing') + // ? storage.get('profileKey') + // : null; let recipients = _.intersection(intendedRecipients, currentRecipients); recipients = _.without(recipients, successfulRecipients); @@ -1031,65 +1031,42 @@ const quoteWithData = await loadQuoteData(this.get('quote')); const previewWithData = await loadPreviewData(this.get('preview')); - + const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ + body, + timestamp: this.get('sent_at'), + attachments, + quote: quoteWithData, + preview: previewWithData, + 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) { - const [number] = recipients; - const dataMessage = await textsecure.messaging.getMessageProto( - number, - body, - attachments, - quoteWithData, - previewWithData, - this.get('sent_at'), - this.get('expireTimer'), - profileKey - ); - return this.sendSyncMessageOnly(dataMessage); + this.trigger('pending'); + // FIXME audric add back profileKey + return libsession.getMessageQueue().sendSyncMessage(chatMessage); } - let promise; - const options = conversation.getSendOptions(); - options.messageType = this.get('type'); - if (conversation.isPrivate()) { const [number] = recipients; - promise = textsecure.messaging.sendMessageToNumber( - number, - body, - attachments, - quoteWithData, - previewWithData, - this.get('sent_at'), - this.get('expireTimer'), - profileKey, - options - ); - } else { - // Because this is a partial group send, we manually construct the request like - // sendMessageToGroup does. - - promise = textsecure.messaging.sendMessage( - { - recipients, - body, - timestamp: this.get('sent_at'), - attachments, - quote: quoteWithData, - preview: previewWithData, - needsSync: !this.get('synced'), - expireTimer: this.get('expireTimer'), - profileKey, - group: { - id: this.get('conversationId'), - type: textsecure.protobuf.GroupContext.Type.DELIVER, - }, - }, - options - ); - } + const recipientPubKey = new libsession.Types.PubKey(number); + this.trigger('pending'); - return this.send(conversation.wrapSend(promise)); + return libsession + .getMessageQueue() + .sendUsingMultiDevice(recipientPubKey, chatMessage); + } + // Because this is a partial group send, we manually construct the request like + // sendMessageToGroup does. + this.trigger('pending'); + // TODO should we handle open groups message here too? + // Not sure there is the concept of retrySend for those + const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( + { + chatMessage, + groupId: this.get('conversationId'), + } + ); + return libsession.getMessageQueue().sendToGroup(closedGroupChatMessage); }, isReplayableError(e) { return ( @@ -1113,7 +1090,6 @@ return null; } - const profileKey = null; const attachmentsWithData = await Promise.all( (this.get('attachments') || []).map(loadAttachmentData) ); @@ -1125,38 +1101,41 @@ const quoteWithData = await loadQuoteData(this.get('quote')); const previewWithData = await loadPreviewData(this.get('preview')); + const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ + body, + timestamp: this.get('sent_at'), + attachments, + quote: quoteWithData, + preview: previewWithData, + expireTimer: this.get('expireTimer'), + }); // Special-case the self-send case - we send only a sync message if (number === this.OUR_NUMBER) { - const dataMessage = await textsecure.messaging.getMessageProto( - number, - body, - attachments, - quoteWithData, - previewWithData, - this.get('sent_at'), - this.get('expireTimer'), - profileKey - ); - return this.sendSyncMessageOnly(dataMessage); + this.trigger('pending'); + return libsession.getMessageQueue().sendSyncMessage(chatMessage); } + const conversation = this.getConversation(); + const recipientPubKey = new libsession.Types.PubKey(number); - const { wrap, sendOptions } = ConversationController.prepareForSend( - number - ); - const promise = textsecure.messaging.sendMessageToNumber( - number, - body, - attachments, - quoteWithData, - previewWithData, - this.get('sent_at'), - this.get('expireTimer'), - profileKey, - sendOptions - ); + if (conversation.isPrivate()) { + this.trigger('pending'); + return libsession + .getMessageQueue() + .sendUsingMultiDevice(recipientPubKey, chatMessage); + } - return this.send(wrap(promise)); + const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( + { + chatMessage, + groupId: this.get('conversationId'), + } + ); + // resend tries to send the message to that specific user only in the context of a closed group + this.trigger('pending'); + return libsession + .getMessageQueue() + .sendUsingMultiDevice(recipientPubKey, closedGroupChatMessage); }, removeOutgoingErrors(number) { const errors = _.partition( From c5cf7f395f64581e8f3b2ff7534af3cc9f7962df Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Jun 2020 17:05:48 +1000 Subject: [PATCH 03/13] remove sendMessageToNumber and sendMessageToGroup --- js/models/conversations.js | 97 ++++++++++++------------------------ js/models/messages.js | 65 ++++++++++-------------- libtextsecure/sendmessage.js | 94 ---------------------------------- 3 files changed, 58 insertions(+), 198 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index a99ccbccc..3b99c6bda 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1205,10 +1205,10 @@ const expireTimer = this.get('expireTimer'); const recipients = this.getRecipients(); - let profileKey; - if (this.get('profileSharing')) { - profileKey = storage.get('profileKey'); - } + // let profileKey; + // if (this.get('profileSharing')) { + // profileKey = storage.get('profileKey'); + // } this.queueJob(async () => { const now = Date.now(); @@ -1304,19 +1304,22 @@ now, }); + // FIXME audric add back profileKey + const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ + body: messageBody, + timestamp: Date.now(), + attachments: finalAttachments, + expireTimer, + preview, + quote, + }); + // Start handle ChatMessages (attachments/quote/preview/body) + // FIXME AUDRIC handle attachments, quote, preview, profileKey + // Special-case the self-send case - we send only a sync message if (this.isMe()) { - const dataMessage = await textsecure.messaging.getMessageProto( - destination, - messageBody, - finalAttachments, - quote, - preview, - now, - expireTimer, - profileKey - ); - return message.sendSyncMessageOnly(dataMessage); + await message.markMessageSyncOnly(); + return libsession.getMessageQueue().sendSyncMessage(chatMessage); } const options = {}; @@ -1364,42 +1367,14 @@ .getMessageQueue() .sendUsingMultiDevice(destinationPubkey, groupInvitMessage); } - const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ - body, - timestamp: Date.now(), - }); - // Start handle ChatMessages (attachments/quote/preview/body) - // FIXME AUDRIC handle attachments, quote, preview + if (conversationType === Message.PRIVATE) { - await libsession + return libsession .getMessageQueue() .sendUsingMultiDevice(destinationPubkey, chatMessage); + } - // return textsecure.messaging.sendMessageToNumber( - // destination, - // messageBody, - // finalAttachments, - // quote, - // preview, - // now, - // expireTimer, - // profileKey, - // {} - // ); - } else if (conversationType === Message.GROUP) { - // return textsecure.messaging.sendMessageToGroup( - // dest, - // numbers, - // messageBody, - // finalAttachments, - // quote, - // preview, - // now, - // expireTimer, - // profileKey, - // {} - // ); - + if (conversationType === Message.GROUP) { // let dest = destination; // let numbers = groupNumbers; if (this.isMediumGroup()) { @@ -1408,7 +1383,7 @@ // dest = this.id; // numbers = [destination]; // options.isMediumGroup = true; - throw new Error('To implement'); + throw new Error('To implement back'); } else { const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( { @@ -1658,28 +1633,22 @@ profileKey = storage.get('profileKey'); } - if (this.isMe()) { - const flags = - textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; - const dataMessage = await textsecure.messaging.getMessageProto( - this.get('id'), - null, - [], - null, - [], - message.get('sent_at'), - expireTimer, - profileKey, - flags - ); - return message.sendSyncMessageOnly(dataMessage); - } const expireUpdate = { timestamp: message.get('sent_at'), expireTimer, profileKey, }; + if (this.isMe()) { + const expirationTimerMessage = new libsession.Messages.Outgoing.ExpirationTimerUpdateMessage( + expireUpdate + ); + await message.markMessageSyncOnly(); + return libsession + .getMessageQueue() + .sendSyncMessage(expirationTimerMessage); + } + if (this.get('type') === 'private') { const expirationTimerMessage = new libsession.Messages.Outgoing.ExpirationTimerUpdateMessage( expireUpdate diff --git a/js/models/messages.js b/js/models/messages.js index cdb5fa3b4..343db5831 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1043,6 +1043,7 @@ if (recipients.length === 1 && recipients[0] === this.OUR_NUMBER) { this.trigger('pending'); // FIXME audric add back profileKey + await this.markMessageSyncOnly(); return libsession.getMessageQueue().sendSyncMessage(chatMessage); } @@ -1055,8 +1056,7 @@ .getMessageQueue() .sendUsingMultiDevice(recipientPubKey, chatMessage); } - // Because this is a partial group send, we manually construct the request like - // sendMessageToGroup does. + this.trigger('pending'); // TODO should we handle open groups message here too? // Not sure there is the concept of retrySend for those @@ -1066,7 +1066,16 @@ groupId: this.get('conversationId'), } ); - return libsession.getMessageQueue().sendToGroup(closedGroupChatMessage); + // Because this is a partial group send, we send the message with the groupId field set, but individually + // to each recipient listed + return Promise.all( + recipients.map(async r => { + const recipientPubKey = new libsession.Types.PubKey(r); + return libsession + .getMessageQueue() + .sendUsingMultiDevice(recipientPubKey, closedGroupChatMessage); + }) + ); }, isReplayableError(e) { return ( @@ -1113,6 +1122,7 @@ // Special-case the self-send case - we send only a sync message if (number === this.OUR_NUMBER) { this.trigger('pending'); + await this.markMessageSyncOnly(); return libsession.getMessageQueue().sendSyncMessage(chatMessage); } const conversation = this.getConversation(); @@ -1387,46 +1397,21 @@ return false; }, - async sendSyncMessageOnly(dataMessage) { - this.set({ dataMessage }); - - try { - this.set({ - // These are the same as a normal send() - sent_to: [this.OUR_NUMBER], - sent: true, - expirationStartTimestamp: Date.now(), - }); - const result = await this.sendSyncMessage(); - this.set({ - // We have to do this afterward, since we didn't have a previous send! - unidentifiedDeliveries: result ? result.unidentifiedDeliveries : null, - - // These are unique to a Note to Self message - immediately read/delivered - delivered_to: [this.OUR_NUMBER], - read_by: [this.OUR_NUMBER], - }); - } catch (result) { - const errors = (result && result.errors) || [ - new Error('Unknown error'), - ]; - this.set({ errors }); - } finally { - await window.Signal.Data.saveMessage(this.attributes, { - Message: Whisper.Message, - }); - this.trigger('done'); + async markMessageSyncOnly(dataMessage) { + this.set({ + // These are the same as a normal send() + dataMessage, + sent_to: [this.OUR_NUMBER], + sent: true, + expirationStartTimestamp: Date.now(), + }); - const errors = this.get('errors'); - if (errors) { - this.trigger('send-error', errors); - } else { - this.trigger('sent'); - } - } + return window.Signal.Data.saveMessage(this.attributes, { + Message: Whisper.Message, + }); }, - async sendSyncMessage() { + sendSyncMessage() { this.syncPromise = this.syncPromise || Promise.resolve(); const next = async () => { const encodedDataMessage = this.get('dataMessage'); diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index ceae67c30..73058949e 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -661,98 +661,6 @@ MessageSender.prototype = { } }, - async sendMessageToNumber( - number, - messageText, - attachments, - quote, - preview, - timestamp, - expireTimer, - profileKey, - options - ) { - const profile = this.getOurProfile(); - - const { groupInvitation, sessionRestoration } = options; - - return this.sendMessage( - { - recipients: [number], - body: messageText, - timestamp, - attachments, - quote, - preview, - needsSync: true, - expireTimer, - profileKey, - profile, - undefined, - groupInvitation, - sessionRestoration, - }, - options - ); - }, - async sendMessageToGroup( - groupId, - groupNumbers, - messageText, - attachments, - quote, - preview, - timestamp, - expireTimer, - profileKey, - options - ) { - // We always assume that only primary device is a member in the group - const primaryDeviceKey = - window.storage.get('primaryDevicePubKey') || - textsecure.storage.user.getNumber(); - let numbers = groupNumbers.filter(number => number !== primaryDeviceKey); - if (options.isPublic) { - numbers = [groupId]; - } - const profile = this.getOurProfile(); - - let group; - // Medium groups don't need this info - if (!options.isMediumGroup) { - group = { - id: groupId, - type: textsecure.protobuf.GroupContext.Type.DELIVER, - }; - } - - const attrs = { - recipients: numbers, - body: messageText, - timestamp, - attachments, - quote, - preview, - needsSync: true, - expireTimer, - profileKey, - profile, - group, - }; - - if (numbers.length === 0) { - return { - successfulNumbers: [], - failoverNumbers: [], - errors: [], - unidentifiedDeliveries: [], - dataMessage: await this.getMessageProtoObj(attrs), - }; - } - - return this.sendMessage(attrs, options); - }, - async updateMediumGroup(members, groupUpdateProto) { // Automatically request session if not found (updates use pairwise sessions) const autoSession = true; @@ -791,9 +699,7 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( sender ); - this.sendMessageToNumber = sender.sendMessageToNumber.bind(sender); this.sendMessage = sender.sendMessage.bind(sender); - this.sendMessageToGroup = sender.sendMessageToGroup.bind(sender); this.updateMediumGroup = sender.updateMediumGroup.bind(sender); this.requestSenderKeys = sender.requestSenderKeys.bind(sender); this.uploadAvatar = sender.uploadAvatar.bind(sender); From df028b7ac68ad693acba4b6115d1fde191c2bea2 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Jun 2020 17:10:43 +1000 Subject: [PATCH 04/13] remove sendMessage() --- js/models/conversations.js | 4 +--- libtextsecure/sendmessage.js | 31 ------------------------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 3b99c6bda..8744c2fa8 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -2019,9 +2019,7 @@ this.ourNumber, { syncMessage: true } ); - await this.wrapSend( - textsecure.messaging.syncReadMessages(read, sendOptions) - ); + await textsecure.messaging.syncReadMessages(read, sendOptions); // FIXME AUDRIC // if (storage.get('read-receipt-setting')) { diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 73058949e..656941eb9 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -351,36 +351,6 @@ MessageSender.prototype = { }); }, - async sendMessage(attrs, options) { - const message = new Message(attrs); - const silent = false; - const publicServer = - options.publicSendData && options.publicSendData.serverAPI; - - await Promise.all([ - this.uploadAttachments(message, publicServer), - this.uploadThumbnails(message, publicServer), - this.uploadLinkPreviews(message, publicServer), - ]); - - return new Promise((resolve, reject) => { - this.sendMessageProto( - message.timestamp, - message.recipients, - message.toProto(), - res => { - res.dataMessage = message.toArrayBuffer(); - if (res.errors.length > 0) { - reject(res); - } else { - resolve(res); - } - }, - silent, - options - ); - }); - }, sendMessageProto( timestamp, numbers, @@ -699,7 +669,6 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( sender ); - this.sendMessage = sender.sendMessage.bind(sender); this.updateMediumGroup = sender.updateMediumGroup.bind(sender); this.requestSenderKeys = sender.requestSenderKeys.bind(sender); this.uploadAvatar = sender.uploadAvatar.bind(sender); From a43abfd436bd89f2f8df56c522897a7504f0abb8 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 10:56:53 +1000 Subject: [PATCH 05/13] move groupContextType to sub classes of Closedgroup --- .../content/data/group/ClosedGroupChatMessage.ts | 8 ++++++-- .../content/data/group/ClosedGroupLeaveMessage.ts | 9 +++++++-- .../outgoing/content/data/group/ClosedGroupMessage.ts | 5 +---- .../content/data/group/ClosedGroupRequestInfoMessage.ts | 8 ++++++-- .../content/data/group/ClosedGroupUpdateMessage.ts | 8 +++----- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/ts/session/messages/outgoing/content/data/group/ClosedGroupChatMessage.ts b/ts/session/messages/outgoing/content/data/group/ClosedGroupChatMessage.ts index a0f75f4b0..4bdc144e8 100644 --- a/ts/session/messages/outgoing/content/data/group/ClosedGroupChatMessage.ts +++ b/ts/session/messages/outgoing/content/data/group/ClosedGroupChatMessage.ts @@ -25,8 +25,12 @@ export class ClosedGroupChatMessage extends ClosedGroupMessage { return this.getDefaultTTL(); } - protected groupContextType(): SignalService.GroupContext.Type { - return SignalService.GroupContext.Type.DELIVER; + protected groupContext(): SignalService.GroupContext { + // use the parent method to fill id correctly + const groupContext = super.groupContext(); + groupContext.type = SignalService.GroupContext.Type.DELIVER; + + return groupContext; } protected dataProto(): SignalService.DataMessage { diff --git a/ts/session/messages/outgoing/content/data/group/ClosedGroupLeaveMessage.ts b/ts/session/messages/outgoing/content/data/group/ClosedGroupLeaveMessage.ts index 29622a13e..1db46ea83 100644 --- a/ts/session/messages/outgoing/content/data/group/ClosedGroupLeaveMessage.ts +++ b/ts/session/messages/outgoing/content/data/group/ClosedGroupLeaveMessage.ts @@ -13,7 +13,12 @@ export class ClosedGroupLeaveMessage extends ClosedGroupMessage { }); } - protected groupContextType(): SignalService.GroupContext.Type { - return SignalService.GroupContext.Type.QUIT; + protected groupContext(): SignalService.GroupContext { + // use the parent method to fill id correctly + const groupContext = super.groupContext(); + + groupContext.type = SignalService.GroupContext.Type.QUIT; + + return groupContext; } } diff --git a/ts/session/messages/outgoing/content/data/group/ClosedGroupMessage.ts b/ts/session/messages/outgoing/content/data/group/ClosedGroupMessage.ts index 91bb9a874..7586cc3ab 100644 --- a/ts/session/messages/outgoing/content/data/group/ClosedGroupMessage.ts +++ b/ts/session/messages/outgoing/content/data/group/ClosedGroupMessage.ts @@ -23,13 +23,10 @@ export abstract class ClosedGroupMessage extends DataMessage { return this.getDefaultTTL(); } - protected abstract groupContextType(): SignalService.GroupContext.Type; - protected groupContext(): SignalService.GroupContext { const id = new Uint8Array(StringUtils.encode(this.groupId.key, 'utf8')); - const type = this.groupContextType(); - return new SignalService.GroupContext({ id, type }); + return new SignalService.GroupContext({ id }); } protected dataProto(): SignalService.DataMessage { diff --git a/ts/session/messages/outgoing/content/data/group/ClosedGroupRequestInfoMessage.ts b/ts/session/messages/outgoing/content/data/group/ClosedGroupRequestInfoMessage.ts index 43a9cad0b..ac8beb3a5 100644 --- a/ts/session/messages/outgoing/content/data/group/ClosedGroupRequestInfoMessage.ts +++ b/ts/session/messages/outgoing/content/data/group/ClosedGroupRequestInfoMessage.ts @@ -13,7 +13,11 @@ export class ClosedGroupRequestInfoMessage extends ClosedGroupMessage { }); } - protected groupContextType(): SignalService.GroupContext.Type { - return SignalService.GroupContext.Type.REQUEST_INFO; + protected groupContext(): SignalService.GroupContext { + // use the parent method to fill id correctly + const groupContext = super.groupContext(); + groupContext.type = SignalService.GroupContext.Type.REQUEST_INFO; + + return groupContext; } } diff --git a/ts/session/messages/outgoing/content/data/group/ClosedGroupUpdateMessage.ts b/ts/session/messages/outgoing/content/data/group/ClosedGroupUpdateMessage.ts index e416394fc..3c4aa14c0 100644 --- a/ts/session/messages/outgoing/content/data/group/ClosedGroupUpdateMessage.ts +++ b/ts/session/messages/outgoing/content/data/group/ClosedGroupUpdateMessage.ts @@ -52,14 +52,12 @@ export abstract class ClosedGroupUpdateMessage extends ClosedGroupMessage { this.avatar = params.avatar; } - protected groupContextType(): SignalService.GroupContext.Type { - return SignalService.GroupContext.Type.UPDATE; - } - protected groupContext(): SignalService.GroupContext { - // use the parent method to fill id and type correctly + // use the parent method to fill id correctly const groupContext = super.groupContext(); + groupContext.type = SignalService.GroupContext.Type.UPDATE; + if (this.name) { groupContext.name = this.name; } From 39bad87a184810efd0ba87f74b5bec9badbb2379 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 10:57:26 +1000 Subject: [PATCH 06/13] updateMediumGroup replaced with new pipeline --- js/models/conversations.js | 38 +++++++------ libtextsecure/message_receiver.js | 11 +++- libtextsecure/sendmessage.js | 29 ++++------ ts/receiver/mediumGroups.ts | 53 +++++++++++-------- .../messages/outgoing/content/data/index.ts | 1 + .../mediumgroup/MediumGroupCreateMessage.ts | 49 +++++++++++++++++ .../data/mediumgroup/MediumGroupMessage.ts | 36 +++++++++++++ .../MediumGroupRequestKeysMessage.ts | 13 +++++ .../MediumGroupResponseKeysMessage.ts | 37 +++++++++++++ .../content/data/mediumgroup/index.ts | 4 ++ 10 files changed, 210 insertions(+), 61 deletions(-) create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/index.ts diff --git a/js/models/conversations.js b/js/models/conversations.js index 8744c2fa8..8b2362ff5 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1813,26 +1813,32 @@ if (groupUpdate.is_medium_group) { // Constructing a "create group" message - const proto = new textsecure.protobuf.DataMessage(); - - const mgUpdate = new textsecure.protobuf.MediumGroupUpdate(); - const { id, name, secretKey, senderKey, members } = groupUpdate; + const { chainKey, keyIdx } = senderKey; - mgUpdate.type = textsecure.protobuf.MediumGroupUpdate.Type.NEW_GROUP; - mgUpdate.groupId = id; - mgUpdate.groupSecretKey = secretKey; - mgUpdate.senderKey = new textsecure.protobuf.SenderKey(senderKey); - mgUpdate.members = members.map(pkHex => - StringView.hexToArrayBuffer(pkHex) - ); - mgUpdate.groupName = name; - mgUpdate.admins = this.get('groupAdmins'); - proto.mediumGroupUpdate = mgUpdate; + const createParams = { + timestamp: Date.now(), + groupId: id, + groupSecretKey: secretKey, + members: members.map(pkHex => StringView.hexToArrayBuffer(pkHex)), + groupName: name, + admins: this.get('groupAdmins'), + chainKey, + keyIdx, + }; - message.send( - this.wrapSend(textsecure.messaging.updateMediumGroup(members, proto)) + const mediumGroupCreateMessage = new libsession.Messages.Outgoing.MediumGroupCreateMessage( + createParams ); + message.trigger('pending'); + + members.forEach(member => { + const memberPubKey = new libsession.Types.PubKey(member); + libsession + .getMessageQueue() + .sendUsingMultiDevice(memberPubKey, mediumGroupCreateMessage); + }); + return; } diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 7c0b48aba..e23e917d4 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -850,8 +850,15 @@ MessageReceiver.prototype.extend({ groupId ); - textsecure.messaging.requestSenderKeys(senderIdentity, groupId); - + const params = { + timestamp: Date.now(), + groupId, + }; + const requestKeysMessage = new libsession.Messages.Outgoing.MediumGroupRequestKeysMessage( + params + ); + const senderPubKey = new libsession.Types.PubKey(senderIdentity); + libsession.getMessageQueue().send(senderPubKey, requestKeysMessage); return; } diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 656941eb9..bbedbc947 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -631,26 +631,16 @@ MessageSender.prototype = { } }, - async updateMediumGroup(members, groupUpdateProto) { - // Automatically request session if not found (updates use pairwise sessions) - const autoSession = true; - - await this.sendGroupProto(members, groupUpdateProto, Date.now(), { - isPublic: false, - autoSession, - }); - - return true; - }, - requestSenderKeys(sender, groupId) { - const proto = new textsecure.protobuf.DataMessage(); - const update = new textsecure.protobuf.MediumGroupUpdate(); - update.type = textsecure.protobuf.MediumGroupUpdate.Type.SENDER_KEY_REQUEST; - update.groupId = groupId; - proto.mediumGroupUpdate = update; - - textsecure.messaging.updateMediumGroup([sender], proto); + const params = { + timestamp: Date.now(), + groupId, + }; + const requestKeysMessage = new libsession.Messages.Outgoing.MediumGroupRequestKeysMessage( + params + ); + const senderPubKey = new libsession.Types.PubKey(sender); + libsession.getMessageQueue().send(senderPubKey, requestKeysMessage); }, makeProxiedRequest(url, options) { return this.server.makeProxiedRequest(url, options); @@ -669,7 +659,6 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( sender ); - this.updateMediumGroup = sender.updateMediumGroup.bind(sender); this.requestSenderKeys = sender.requestSenderKeys.bind(sender); this.uploadAvatar = sender.uploadAvatar.bind(sender); this.syncReadMessages = sender.syncReadMessages.bind(sender); diff --git a/ts/receiver/mediumGroups.ts b/ts/receiver/mediumGroups.ts index b47ea51da..be2010a56 100644 --- a/ts/receiver/mediumGroups.ts +++ b/ts/receiver/mediumGroups.ts @@ -1,6 +1,9 @@ import { SignalService } from '../protobuf'; import { removeFromCache } from './cache'; import { EnvelopePlus } from './types'; +import { MediumGroupResponseKeysMessage } from '../session/messages/outgoing'; +import { getMessageQueue } from '../session'; +import { PubKey } from '../session/types'; async function handleSenderKeyRequest( envelope: EnvelopePlus, @@ -14,26 +17,26 @@ async function handleSenderKeyRequest( log.debug('[sender key] sender key request from:', senderIdentity); - const proto = new SignalService.DataMessage(); - // We reuse the same message type for sender keys - const update = new SignalService.MediumGroupUpdate(); - const { chainKey, keyIdx } = await SenderKeyAPI.getSenderKeys( groupId, ourIdentity ); - update.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; - update.groupId = groupId; - update.senderKey = new SignalService.SenderKey({ - chainKey: StringView.arrayBufferToHex(chainKey), + const chainKeyHex = StringView.arrayBufferToHex(chainKey); + const responseParams = { + timestamp: Date.now(), + groupId, + chainKey: chainKeyHex, keyIdx, - }); + }; - proto.mediumGroupUpdate = update; + const keysResponseMessage = new MediumGroupResponseKeysMessage( + responseParams + ); - textsecure.messaging.updateMediumGroup([senderIdentity], proto); + const senderPubKey = new PubKey(senderIdentity); + await getMessageQueue().send(senderPubKey, keysResponseMessage); removeFromCache(envelope); } @@ -157,7 +160,7 @@ async function handleNewGroup(envelope: EnvelopePlus, groupUpdate: any) { senderKey.keyIdx ); - const ownSenderKey = await SenderKeyAPI.createSenderKeyForGroup( + const ownSenderKeyHex = await SenderKeyAPI.createSenderKeyForGroup( groupId, ourIdentity ); @@ -166,20 +169,24 @@ async function handleNewGroup(envelope: EnvelopePlus, groupUpdate: any) { // Send own key to every member const otherMembers = _.without(members, ourIdentity); - const proto = new SignalService.DataMessage(); - // We reuse the same message type for sender keys - const update = new SignalService.MediumGroupUpdate(); - update.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; - update.groupId = groupId; - update.senderKey = new SignalService.SenderKey({ - chainKey: ownSenderKey, + const responseParams = { + timestamp: Date.now(), + groupId, + chainKey: ownSenderKeyHex, keyIdx: 0, + }; + + const keysResponseMessage = new MediumGroupResponseKeysMessage( + responseParams + ); + // send our senderKey to every other member + otherMembers.forEach((member: string) => { + const memberPubKey = new PubKey(member); + getMessageQueue() + .sendUsingMultiDevice(memberPubKey, keysResponseMessage) + .ignore(); }); - - proto.mediumGroupUpdate = update; - - textsecure.messaging.updateMediumGroup(otherMembers, proto); } // TODO: !!!! This will need to be re-enabled after message polling refactor !!!!! diff --git a/ts/session/messages/outgoing/content/data/index.ts b/ts/session/messages/outgoing/content/data/index.ts index a8022724b..c76911036 100644 --- a/ts/session/messages/outgoing/content/data/index.ts +++ b/ts/session/messages/outgoing/content/data/index.ts @@ -3,4 +3,5 @@ export * from './DeviceUnlinkMessage'; export * from './GroupInvitationMessage'; export * from './ChatMessage'; export * from './group'; +export * from './mediumgroup'; export * from './ExpirationTimerUpdateMessage'; diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts new file mode 100644 index 000000000..aed1cc1c3 --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts @@ -0,0 +1,49 @@ +import { SignalService } from '../../../../../../protobuf'; +import { + MediumGroupResponseKeysMessage, + MediumGroupResponseKeysParams, +} from './MediumGroupResponseKeysMessage'; + +interface MediumGroupCreateParams extends MediumGroupResponseKeysParams { + groupSecretKey: Uint8Array; + members: Array; + admins: Array; + groupName: string; +} + +export abstract class MediumGroupCreateMessage extends MediumGroupResponseKeysMessage { + public readonly groupSecretKey: Uint8Array; + public readonly members: Array; + public readonly admins: Array; + public readonly groupName: string; + + constructor({ + timestamp, + identifier, + chainKey, + keyIdx, + groupId, + groupSecretKey, + members, + admins, + groupName, + }: MediumGroupCreateParams) { + super({ timestamp, identifier, groupId, chainKey, keyIdx }); + this.groupSecretKey = groupSecretKey; + this.members = members; + this.admins = admins; + this.groupName = groupName; + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = SignalService.MediumGroupUpdate.Type.NEW_GROUP; + mediumGroupContext.groupSecretKey = this.groupSecretKey; + mediumGroupContext.members = this.members; + mediumGroupContext.admins = this.admins; + mediumGroupContext.groupName = this.groupName; + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts new file mode 100644 index 000000000..6f5f7514b --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts @@ -0,0 +1,36 @@ +import { DataMessage } from '../DataMessage'; +import { SignalService } from '../../../../../../protobuf'; +import { MessageParams } from '../../../Message'; +import { PubKey } from '../../../../../types'; +import { StringUtils } from '../../../../../utils'; + +export interface MediumGroupMessageParams extends MessageParams { + groupId: string | PubKey; +} + +export abstract class MediumGroupMessage extends DataMessage { + public readonly groupId: PubKey; + + constructor(params: MediumGroupMessageParams) { + super({ + timestamp: params.timestamp, + identifier: params.identifier, + }); + this.groupId = PubKey.cast(params.groupId); + } + + public ttl(): number { + return this.getDefaultTTL(); + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + return new SignalService.MediumGroupUpdate({ groupId: this.groupId.key }); + } + + protected dataProto(): SignalService.DataMessage { + const dataMessage = new SignalService.DataMessage(); + dataMessage.mediumGroupUpdate = this.mediumGroupContext(); + + return dataMessage; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts new file mode 100644 index 000000000..5cc6499cc --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts @@ -0,0 +1,13 @@ +import { SignalService } from '../../../../../../protobuf'; +import { MediumGroupMessage } from '.'; + +export class MediumGroupRequestKeysMessage extends MediumGroupMessage { + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = + SignalService.MediumGroupUpdate.Type.SENDER_KEY_REQUEST; + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts new file mode 100644 index 000000000..3dbd8d66c --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts @@ -0,0 +1,37 @@ +import { SignalService } from '../../../../../../protobuf'; +import { MediumGroupMessage, MediumGroupMessageParams } from '.'; + +export interface MediumGroupResponseKeysParams + extends MediumGroupMessageParams { + chainKey: string; + keyIdx: number; +} + +export class MediumGroupResponseKeysMessage extends MediumGroupMessage { + public readonly chainKey: string; + public readonly keyIdx: number; + + constructor({ + timestamp, + identifier, + groupId, + chainKey, + keyIdx, + }: MediumGroupResponseKeysParams) { + super({ timestamp, identifier, groupId }); + this.chainKey = chainKey; + this.keyIdx = keyIdx; + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; + mediumGroupContext.senderKey = new SignalService.SenderKey({ + chainKey: this.chainKey, + keyIdx: this.keyIdx, + }); + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/index.ts b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts new file mode 100644 index 000000000..f6b317532 --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts @@ -0,0 +1,4 @@ +export * from './MediumGroupMessage'; +export * from './MediumGroupRequestKeysMessage'; +export * from './MediumGroupResponseKeysMessage'; +export * from './MediumGroupCreateMessage'; From 23d22622cad1c21e5b23afc4f4d9d56aa64f5cd6 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 11:08:49 +1000 Subject: [PATCH 07/13] remove unused methods on sendMessage.js --- libtextsecure/sendmessage.js | 135 ----------------------------------- 1 file changed, 135 deletions(-) diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index bbedbc947..3c37e6d45 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -351,31 +351,6 @@ MessageSender.prototype = { }); }, - sendMessageProto( - timestamp, - numbers, - message, - callback, - silent, - options = {} - ) { - // Note: Since we're just doing independant tasks, - // using `async` in the `forEach` loop should be fine. - // If however we want to use the results from forEach then - // we would need to convert this to a Promise.all(numbers.map(...)) - numbers.forEach(async number => { - const outgoing = new OutgoingMessage( - this.server, - timestamp, - numbers, - message, - silent, - callback, - options - ); - this.queueJobForNumber(number, () => outgoing.sendToNumber(number)); - }); - }, uploadAvatar(attachment) { // isRaw is true since the data is already encrypted @@ -521,103 +496,6 @@ MessageSender.prototype = { return libsession.getMessageQueue().sendSyncMessage(verifiedSyncMessage); }, - async sendGroupProto( - providedNumbers, - proto, - timestamp = Date.now(), - options = {} - ) { - // We always assume that only primary device is a member in the group - const primaryDeviceKey = - window.storage.get('primaryDevicePubKey') || - textsecure.storage.user.getNumber(); - const numbers = providedNumbers.filter( - number => number !== primaryDeviceKey - ); - if (numbers.length === 0) { - return Promise.resolve({ - successfulNumbers: [], - failoverNumbers: [], - errors: [], - unidentifiedDeliveries: [], - dataMessage: proto.toArrayBuffer(), - }); - } - - const sendPromise = new Promise((resolve, reject) => { - const silent = true; - const callback = res => { - res.dataMessage = proto.toArrayBuffer(); - if (res.errors.length > 0) { - reject(res); - } else { - resolve(res); - } - }; - - this.sendMessageProto( - timestamp, - numbers, - proto, - callback, - silent, - options - ); - }); - - const result = await sendPromise; - - // Sync the group message to our other devices - const sentSyncMessageParams = { - timestamp, - dataMessage: proto, - }; - const sentSyncMessage = new libsession.Messages.Outgoing.SentSyncMessage( - sentSyncMessageParams - ); - - await libsession.getMessageQueue().sendSyncMessage(sentSyncMessage); - - return result; - }, - - async getMessageProto( - number, - body, - attachments, - quote, - preview, - timestamp, - expireTimer, - profileKey, - flags - ) { - const attributes = { - recipients: [number], - body, - timestamp, - attachments, - quote, - preview, - expireTimer, - profileKey, - flags, - }; - - return this.getMessageProtoObj(attributes); - }, - - async getMessageProtoObj(attributes) { - const message = new Message(attributes); - await Promise.all([ - this.uploadAttachments(message), - this.uploadThumbnails(message), - this.uploadLinkPreviews(message), - ]); - - return message.toArrayBuffer(); - }, - getOurProfile() { try { // Secondary devices have their profile stored @@ -631,17 +509,6 @@ MessageSender.prototype = { } }, - requestSenderKeys(sender, groupId) { - const params = { - timestamp: Date.now(), - groupId, - }; - const requestKeysMessage = new libsession.Messages.Outgoing.MediumGroupRequestKeysMessage( - params - ); - const senderPubKey = new libsession.Types.PubKey(sender); - libsession.getMessageQueue().send(senderPubKey, requestKeysMessage); - }, makeProxiedRequest(url, options) { return this.server.makeProxiedRequest(url, options); }, @@ -659,13 +526,11 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( sender ); - this.requestSenderKeys = sender.requestSenderKeys.bind(sender); this.uploadAvatar = sender.uploadAvatar.bind(sender); this.syncReadMessages = sender.syncReadMessages.bind(sender); this.syncVerification = sender.syncVerification.bind(sender); this.makeProxiedRequest = sender.makeProxiedRequest.bind(sender); this.getProxiedSize = sender.getProxiedSize.bind(sender); - this.getMessageProto = sender.getMessageProto.bind(sender); }; textsecure.MessageSender.prototype = { From 9941c125865d66d39230995eb2899910d2092e5f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 13:53:33 +1000 Subject: [PATCH 08/13] finish adding mediumGroupUpdates --- js/background.js | 26 +++++++--------- js/models/conversations.js | 23 +++++++++----- libtextsecure/sendmessage.js | 3 +- .../mediumgroup/MediumGroupChatMessage.ts | 30 +++++++++++++++++++ .../content/data/mediumgroup/index.ts | 1 + 5 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupChatMessage.ts diff --git a/js/background.js b/js/background.js index 1b6de3a46..9b9cf706b 100644 --- a/js/background.js +++ b/js/background.js @@ -1621,22 +1621,16 @@ }); if (Whisper.Import.isComplete()) { - // FIXME Audric; Is that needed for us? - // const { - // wrap, - // sendOptions, - // } = ConversationController.prepareForSend( - // textsecure.storage.user.getNumber(), - // { syncMessage: true } - // ); - // wrap( - // textsecure.messaging.sendRequestConfigurationSyncMessage(sendOptions) - // ).catch(error => { - // window.log.error( - // 'Import complete, but failed to send sync message', - // error && error.stack ? error.stack : error - // ); - // }); + const { CONFIGURATION } = textsecure.protobuf.SyncMessage.Request.Type; + const { RequestSyncMessage } = window.libsession.Messages.Outgoing; + + const requestConfigurationSyncMessage = new RequestSyncMessage({ + timestamp: Date.now(), + reqestType: CONFIGURATION, + }); + await libsession + .getMessageQueue() + .sendSyncMessage(requestConfigurationSyncMessage); } } diff --git a/js/models/conversations.js b/js/models/conversations.js index 8b2362ff5..46b1e1d85 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1375,15 +1375,22 @@ } if (conversationType === Message.GROUP) { - // let dest = destination; - // let numbers = groupNumbers; if (this.isMediumGroup()) { - // FIXME audric to implement back - - // dest = this.id; - // numbers = [destination]; - // options.isMediumGroup = true; - throw new Error('To implement back'); + const mediumGroupChatMessage = new libsession.Messages.Outgoing.MediumGroupChatMessage( + { + chatMessage, + groupId: destination, + } + ); + const members = this.get('members'); + await Promise.all( + members.map(async m => { + const memberPubKey = new libsession.Types.PubKey(m); + await libsession + .getMessageQueue() + .sendUsingMultiDevice(memberPubKey, mediumGroupChatMessage); + }) + ); } else { const closedGroupChatMessage = new libsession.Messages.Outgoing.ClosedGroupChatMessage( { diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 3c37e6d45..f70cb1aa9 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -1,4 +1,4 @@ -/* global textsecure, WebAPI, libsignal, window, OutgoingMessage, libloki, _, libsession */ +/* global textsecure, WebAPI, libsignal, window, libloki, _, libsession */ /* eslint-disable more/no-then, no-bitwise */ @@ -351,7 +351,6 @@ MessageSender.prototype = { }); }, - uploadAvatar(attachment) { // isRaw is true since the data is already encrypted // and doesn't need to be encrypted again diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupChatMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupChatMessage.ts new file mode 100644 index 000000000..59d557ab7 --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupChatMessage.ts @@ -0,0 +1,30 @@ +import { SignalService } from '../../../../../../protobuf'; +import { ChatMessage } from '../ChatMessage'; +import { PubKey } from '../../../../../types'; +import { MediumGroupMessage } from './MediumGroupMessage'; + +interface MediumGroupChatMessageParams { + identifier?: string; + groupId: string | PubKey; + chatMessage: ChatMessage; +} + +export class MediumGroupChatMessage extends MediumGroupMessage { + private readonly chatMessage: ChatMessage; + + constructor(params: MediumGroupChatMessageParams) { + super({ + timestamp: params.chatMessage.timestamp, + identifier: params.identifier ?? params.chatMessage.identifier, + groupId: params.groupId, + }); + this.chatMessage = params.chatMessage; + } + + protected dataProto(): SignalService.DataMessage { + const messageProto = this.chatMessage.dataProto(); + messageProto.mediumGroupUpdate = super.dataProto().mediumGroupUpdate; + + return messageProto; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/index.ts b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts index f6b317532..25f87eb5f 100644 --- a/ts/session/messages/outgoing/content/data/mediumgroup/index.ts +++ b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts @@ -2,3 +2,4 @@ export * from './MediumGroupMessage'; export * from './MediumGroupRequestKeysMessage'; export * from './MediumGroupResponseKeysMessage'; export * from './MediumGroupCreateMessage'; +export * from './MediumGroupChatMessage'; From 67a9fcaa4637846fcac3788f129aa5be6dc06a07 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 13:54:08 +1000 Subject: [PATCH 09/13] remove calls to message.sendSyncMessage() --- js/models/messages.js | 51 ------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/js/models/messages.js b/js/models/messages.js index 343db5831..30cade846 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1305,15 +1305,6 @@ }); this.trigger('sent', this); - // don't send sync message for EndSession messages - if (!this.isEndSession()) { - const c = this.getConversation(); - // Don't bother sending sync messages to public chats - // or groups with sender keys - if (c && !c.isPublic() && !c.isMediumGroup()) { - this.sendSyncMessage(); - } - } }) .catch(result => { this.trigger('done'); @@ -1358,7 +1349,6 @@ expirationStartTimestamp, unidentifiedDeliveries: result.unidentifiedDeliveries, }); - promises.push(this.sendSyncMessage()); } else { this.saveErrors(result.errors); } @@ -1411,47 +1401,6 @@ }); }, - sendSyncMessage() { - this.syncPromise = this.syncPromise || Promise.resolve(); - const next = async () => { - const encodedDataMessage = this.get('dataMessage'); - if (this.get('synced') || !encodedDataMessage) { - return Promise.resolve(); - } - const dataMessage = textsecure.protobuf.DataMessage.decode( - encodedDataMessage - ); - // Sync the group message to our other devices - const sentSyncMessageParams = { - timestamp: this.get('sent_at'), - dataMessage, - destination: this.get('destination'), - expirationStartTimestamp: this.get('expirationStartTimestamp'), - sent_to: this.get('sent_to'), - unidentifiedDeliveries: this.get('unidentifiedDeliveries'), - }; - const sentSyncMessage = new libsession.Messages.Outgoing.SentSyncMessage( - sentSyncMessageParams - ); - - const result = await libsession - .getMessageQueue() - .sendSyncMessage(sentSyncMessage); - this.set({ - synced: true, - dataMessage: null, - }); - await window.Signal.Data.saveMessage(this.attributes, { - Message: Whisper.Message, - }); - return result; - }; - - this.syncPromise = this.syncPromise.then(next, next); - - return this.syncPromise; - }, - async saveErrors(providedErrors) { let errors = providedErrors; From 1650d758a54bf27236ab4570defd9ceefdbb6871 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 26 Jun 2020 14:08:21 +1000 Subject: [PATCH 10/13] fix calls with NoteToSelf case -> morph the message to a syncMessage --- js/models/conversations.js | 12 ++++++++---- js/models/messages.js | 8 +++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 46b1e1d85..e763d60dd 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1319,7 +1319,10 @@ // Special-case the self-send case - we send only a sync message if (this.isMe()) { await message.markMessageSyncOnly(); - return libsession.getMessageQueue().sendSyncMessage(chatMessage); + const syncMessage = libsession.Utils.SyncMessageUtils.from( + chatMessage + ); + return libsession.getMessageQueue().sendSyncMessage(syncMessage); } const options = {}; @@ -1651,9 +1654,10 @@ expireUpdate ); await message.markMessageSyncOnly(); - return libsession - .getMessageQueue() - .sendSyncMessage(expirationTimerMessage); + const syncMessage = libsession.Utils.SyncMessageUtils.from( + expirationTimerMessage + ); + return libsession.getMessageQueue().sendSyncMessage(syncMessage); } if (this.get('type') === 'private') { diff --git a/js/models/messages.js b/js/models/messages.js index 30cade846..6c3affd0a 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1044,7 +1044,8 @@ this.trigger('pending'); // FIXME audric add back profileKey await this.markMessageSyncOnly(); - return libsession.getMessageQueue().sendSyncMessage(chatMessage); + const syncMessage = libsession.Utils.SyncMessageUtils.from(chatMessage); + return libsession.getMessageQueue().sendSyncMessage(syncMessage); } if (conversation.isPrivate()) { @@ -1058,7 +1059,7 @@ } this.trigger('pending'); - // TODO should we handle open groups message here too? + // 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( { @@ -1123,7 +1124,8 @@ if (number === this.OUR_NUMBER) { this.trigger('pending'); await this.markMessageSyncOnly(); - return libsession.getMessageQueue().sendSyncMessage(chatMessage); + const syncMessage = libsession.Utils.SyncMessageUtils.from(chatMessage); + return libsession.getMessageQueue().sendSyncMessage(syncMessage); } const conversation = this.getConversation(); const recipientPubKey = new libsession.Types.PubKey(number); From 8b4e69739d3dda59d9a1244ff8f3cc67b14be37a Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 29 Jun 2020 10:14:56 +1000 Subject: [PATCH 11/13] adress review --- js/background.js | 5 +++- js/models/conversations.js | 14 ++---------- js/models/messages.js | 43 +++++++++++++++++++---------------- libtextsecure/sendmessage.js | 36 ++++++++++++++++++++++++----- libtextsecure/sync_request.js | 13 ++++++++--- 5 files changed, 69 insertions(+), 42 deletions(-) diff --git a/js/background.js b/js/background.js index 9b9cf706b..6e96fa7ff 100644 --- a/js/background.js +++ b/js/background.js @@ -1628,9 +1628,12 @@ timestamp: Date.now(), reqestType: CONFIGURATION, }); + const myPubKey = textsecure.storage.user.getNumber(); + const currentPubKey = new libsession.Types.PubKey(myPubKey); await libsession .getMessageQueue() - .sendSyncMessage(requestConfigurationSyncMessage); + .sendUsingMultiDevice(currentPubKey, requestConfigurationSyncMessage); + // sending of the message is handled in the 'private' case below } } diff --git a/js/models/conversations.js b/js/models/conversations.js index e763d60dd..6e3dbd861 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1316,13 +1316,9 @@ // Start handle ChatMessages (attachments/quote/preview/body) // FIXME AUDRIC handle attachments, quote, preview, profileKey - // Special-case the self-send case - we send only a sync message if (this.isMe()) { await message.markMessageSyncOnly(); - const syncMessage = libsession.Utils.SyncMessageUtils.from( - chatMessage - ); - return libsession.getMessageQueue().sendSyncMessage(syncMessage); + // sending is done in the 'private' case below } const options = {}; @@ -1650,14 +1646,8 @@ }; if (this.isMe()) { - const expirationTimerMessage = new libsession.Messages.Outgoing.ExpirationTimerUpdateMessage( - expireUpdate - ); await message.markMessageSyncOnly(); - const syncMessage = libsession.Utils.SyncMessageUtils.from( - expirationTimerMessage - ); - return libsession.getMessageQueue().sendSyncMessage(syncMessage); + // sending of the message is handled in the 'private' case below } if (this.get('type') === 'private') { diff --git a/js/models/messages.js b/js/models/messages.js index 6c3affd0a..36787bd7f 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -28,8 +28,8 @@ deleteExternalMessageFiles, getAbsoluteAttachmentPath, loadAttachmentData, - loadQuoteData, - loadPreviewData, + // loadQuoteData, + // loadPreviewData, } = window.Signal.Migrations; const { bytesFromString } = window.Signal.Crypto; @@ -1023,20 +1023,23 @@ const attachmentsWithData = await Promise.all( (this.get('attachments') || []).map(loadAttachmentData) ); - const { body, attachments } = Whisper.Message.getLongMessageAttachment({ + const { body } = Whisper.Message.getLongMessageAttachment({ body: this.get('body'), attachments: attachmentsWithData, now: this.get('sent_at'), }); - - const quoteWithData = await loadQuoteData(this.get('quote')); - const previewWithData = await loadPreviewData(this.get('preview')); + // 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 + // but the main difference is that they haven't been uploaded + // so no url exists in them + // so passing it to chat message is incorrect + + // const quoteWithData = await loadQuoteData(this.get('quote')); + // const previewWithData = await loadPreviewData(this.get('preview')); const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ body, timestamp: this.get('sent_at'), - attachments, - quote: quoteWithData, - preview: previewWithData, expireTimer: this.get('expireTimer'), }); // Special-case the self-send case - we send only a sync message @@ -1044,8 +1047,7 @@ this.trigger('pending'); // FIXME audric add back profileKey await this.markMessageSyncOnly(); - const syncMessage = libsession.Utils.SyncMessageUtils.from(chatMessage); - return libsession.getMessageQueue().sendSyncMessage(syncMessage); + // sending is done in the private case below } if (conversation.isPrivate()) { @@ -1103,20 +1105,22 @@ const attachmentsWithData = await Promise.all( (this.get('attachments') || []).map(loadAttachmentData) ); - const { body, attachments } = Whisper.Message.getLongMessageAttachment({ + const { body } = Whisper.Message.getLongMessageAttachment({ body: this.get('body'), attachments: attachmentsWithData, now: this.get('sent_at'), }); - - const quoteWithData = await loadQuoteData(this.get('quote')); - const previewWithData = await loadPreviewData(this.get('preview')); + // 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 + // but the main difference is that they haven't been uploaded + // so no url exists in them + // so passing it to chat message is incorrect + // const quoteWithData = await loadQuoteData(this.get('quote')); + // const previewWithData = await loadPreviewData(this.get('preview')); const chatMessage = new libsession.Messages.Outgoing.ChatMessage({ body, timestamp: this.get('sent_at'), - attachments, - quote: quoteWithData, - preview: previewWithData, expireTimer: this.get('expireTimer'), }); @@ -1124,8 +1128,7 @@ if (number === this.OUR_NUMBER) { this.trigger('pending'); await this.markMessageSyncOnly(); - const syncMessage = libsession.Utils.SyncMessageUtils.from(chatMessage); - return libsession.getMessageQueue().sendSyncMessage(syncMessage); + // sending is done in the private case below } const conversation = this.getConversation(); const recipientPubKey = new libsession.Types.PubKey(number); diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index f70cb1aa9..d70be1d7f 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -379,8 +379,14 @@ MessageSender.prototype = { const syncMessages = await Promise.all( chunked.map(c => libloki.api.createContactSyncMessage(c)) ); + const pubKey = textsecure.storage.user.getNumber(); + + const currentPubKey = new libsession.Types.PubKey(pubKey); + const syncPromises = syncMessages.map(syncMessage => - libsession.getMessageQueue().sendSyncMessage(syncMessage) + libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, syncMessage) ); return Promise.all(syncPromises); @@ -406,13 +412,17 @@ MessageSender.prototype = { window.console.info('No closed group to sync.'); return Promise.resolve(); } + const pubKey = textsecure.storage.user.getNumber(); + const currentPubKey = new libsession.Types.PubKey(pubKey); // We need to sync across 1 group at a time // This is because we could hit the storage server limit with one group const syncPromises = sessionGroups .map(c => libloki.api.createGroupSyncMessage(c)) .map(syncMessage => - libsession.getMessageQueue().sendSyncMessage(syncMessage) + libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, syncMessage) ); return Promise.all(syncPromises); @@ -448,7 +458,12 @@ MessageSender.prototype = { openGroupsSyncParams ); - return libsession.getMessageQueue().sendSyncMessage(openGroupsSyncMessage); + const pubKey = textsecure.storage.user.getNumber(); + const currentPubKey = new libsession.Types.PubKey(pubKey); + + return libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, openGroupsSyncMessage); }, syncReadMessages(reads) { const myDevice = textsecure.storage.user.getDeviceId(); @@ -459,8 +474,11 @@ MessageSender.prototype = { readMessages: reads, } ); - - return libsession.getMessageQueue().sendSyncMessage(syncReadMessages); + const pubKey = textsecure.storage.user.getNumber(); + const currentPubKey = new libsession.Types.PubKey(pubKey); + return libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, syncReadMessages); } return Promise.resolve(); @@ -492,7 +510,13 @@ MessageSender.prototype = { const verifiedSyncMessage = new window.libsession.Messages.Outgoing.VerifiedSyncMessage( verifiedSyncParams ); - return libsession.getMessageQueue().sendSyncMessage(verifiedSyncMessage); + const pubKey = textsecure.storage.user.getNumber(); + + const currentPubKey = new libsession.Types.PubKey(pubKey); + + return libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, verifiedSyncMessage); }, getOurProfile() { diff --git a/libtextsecure/sync_request.js b/libtextsecure/sync_request.js index f17782566..d5b4ea043 100644 --- a/libtextsecure/sync_request.js +++ b/libtextsecure/sync_request.js @@ -23,9 +23,14 @@ timestamp: Date.now(), reqestType: CONFIGURATION, }); + + const pubKey = textsecure.storage.user.getNumber(); + + const currentPubKey = new libsession.Types.PubKey(pubKey); + await libsession .getMessageQueue() - .sendSyncMessage(requestConfigurationSyncMessage); + .sendUsingMultiDevice(currentPubKey, requestConfigurationSyncMessage); window.log.info('SyncRequest now sending contact sync message...'); const { CONTACTS } = textsecure.protobuf.SyncMessage.Request.Type; @@ -35,7 +40,7 @@ }); await libsession .getMessageQueue() - .sendSyncMessage(requestContactSyncMessage); + .sendUsingMultiDevice(currentPubKey, requestContactSyncMessage); window.log.info('SyncRequest now sending group sync messsage...'); const { GROUPS } = textsecure.protobuf.SyncMessage.Request.Type; @@ -43,7 +48,9 @@ timestamp: Date.now(), reqestType: GROUPS, }); - await libsession.getMessageQueue().sendSyncMessage(requestGroupSyncMessage); + await libsession + .getMessageQueue() + .sendUsingMultiDevice(currentPubKey, requestGroupSyncMessage); this.timeout = setTimeout(this.onTimeout.bind(this), 60000); } From 1b011ca74eda672cb478cda5043a977e504b1ec0 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 29 Jun 2020 10:30:16 +1000 Subject: [PATCH 12/13] fix groupUpdate including an empty kicked field --- ts/components/conversation/GroupNotification.tsx | 4 +--- ts/receiver/queuedJob.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ts/components/conversation/GroupNotification.tsx b/ts/components/conversation/GroupNotification.tsx index 6cac19e26..c01d774a2 100644 --- a/ts/components/conversation/GroupNotification.tsx +++ b/ts/components/conversation/GroupNotification.tsx @@ -79,9 +79,7 @@ export class GroupNotification extends React.Component { } if (!contacts || !contacts.length) { - // FIXME audric - return 'FIXME audric'; - // throw new Error('Group update kicked is missing contacts'); + throw new Error('Group update kicked is missing contacts'); } const kickedKey = diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts index f6022d00e..c1520c09c 100644 --- a/ts/receiver/queuedJob.ts +++ b/ts/receiver/queuedJob.ts @@ -55,7 +55,7 @@ async function handleGroups( if (removedMembers.includes(ourNumber)) { groupUpdate.kicked = 'You'; attributes.isKickedFromGroup = true; - } else { + } else if (removedMembers.length) { groupUpdate.kicked = removedMembers; } } else if (group.type === GROUP_TYPES.QUIT) { From 24f86de0879acb73f820190cd8ccd2ba0bf41e70 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 29 Jun 2020 11:07:13 +1000 Subject: [PATCH 13/13] use SyncMessage when we are only sending a syncMessage --- js/background.js | 4 +-- libtextsecure/sendmessage.js | 46 ++++------------------------------- libtextsecure/sync_request.js | 12 +++------ 3 files changed, 9 insertions(+), 53 deletions(-) diff --git a/js/background.js b/js/background.js index 6e96fa7ff..03aa24766 100644 --- a/js/background.js +++ b/js/background.js @@ -1628,11 +1628,9 @@ timestamp: Date.now(), reqestType: CONFIGURATION, }); - const myPubKey = textsecure.storage.user.getNumber(); - const currentPubKey = new libsession.Types.PubKey(myPubKey); await libsession .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, requestConfigurationSyncMessage); + .sendSyncMessage(requestConfigurationSyncMessage); // sending of the message is handled in the 'private' case below } } diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index d70be1d7f..73d8bad7a 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -379,14 +379,9 @@ MessageSender.prototype = { const syncMessages = await Promise.all( chunked.map(c => libloki.api.createContactSyncMessage(c)) ); - const pubKey = textsecure.storage.user.getNumber(); - - const currentPubKey = new libsession.Types.PubKey(pubKey); const syncPromises = syncMessages.map(syncMessage => - libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, syncMessage) + libsession.getMessageQueue().sendSyncMessage(syncMessage) ); return Promise.all(syncPromises); @@ -412,17 +407,13 @@ MessageSender.prototype = { window.console.info('No closed group to sync.'); return Promise.resolve(); } - const pubKey = textsecure.storage.user.getNumber(); - const currentPubKey = new libsession.Types.PubKey(pubKey); // We need to sync across 1 group at a time // This is because we could hit the storage server limit with one group const syncPromises = sessionGroups .map(c => libloki.api.createGroupSyncMessage(c)) .map(syncMessage => - libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, syncMessage) + libsession.getMessageQueue().sendSyncMessage(syncMessage) ); return Promise.all(syncPromises); @@ -458,12 +449,7 @@ MessageSender.prototype = { openGroupsSyncParams ); - const pubKey = textsecure.storage.user.getNumber(); - const currentPubKey = new libsession.Types.PubKey(pubKey); - - return libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, openGroupsSyncMessage); + return libsession.getMessageQueue().sendSyncMessage(openGroupsSyncMessage); }, syncReadMessages(reads) { const myDevice = textsecure.storage.user.getDeviceId(); @@ -474,11 +460,7 @@ MessageSender.prototype = { readMessages: reads, } ); - const pubKey = textsecure.storage.user.getNumber(); - const currentPubKey = new libsession.Types.PubKey(pubKey); - return libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, syncReadMessages); + return libsession.getMessageQueue().sendSyncMessage(syncReadMessages); } return Promise.resolve(); @@ -510,26 +492,8 @@ MessageSender.prototype = { const verifiedSyncMessage = new window.libsession.Messages.Outgoing.VerifiedSyncMessage( verifiedSyncParams ); - const pubKey = textsecure.storage.user.getNumber(); - const currentPubKey = new libsession.Types.PubKey(pubKey); - - return libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, verifiedSyncMessage); - }, - - getOurProfile() { - try { - // Secondary devices have their profile stored - // in their primary device's conversation - const ourNumber = window.storage.get('primaryDevicePubKey'); - const conversation = window.ConversationController.get(ourNumber); - return conversation.getLokiProfile(); - } catch (e) { - window.log.error(`Failed to get our profile: ${e}`); - return null; - } + return libsession.getMessageQueue().sendSyncMessage(verifiedSyncMessage); }, makeProxiedRequest(url, options) { diff --git a/libtextsecure/sync_request.js b/libtextsecure/sync_request.js index d5b4ea043..069eda64a 100644 --- a/libtextsecure/sync_request.js +++ b/libtextsecure/sync_request.js @@ -24,13 +24,9 @@ reqestType: CONFIGURATION, }); - const pubKey = textsecure.storage.user.getNumber(); - - const currentPubKey = new libsession.Types.PubKey(pubKey); - await libsession .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, requestConfigurationSyncMessage); + .sendSyncMessage(requestConfigurationSyncMessage); window.log.info('SyncRequest now sending contact sync message...'); const { CONTACTS } = textsecure.protobuf.SyncMessage.Request.Type; @@ -40,7 +36,7 @@ }); await libsession .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, requestContactSyncMessage); + .sendSyncMessage(requestContactSyncMessage); window.log.info('SyncRequest now sending group sync messsage...'); const { GROUPS } = textsecure.protobuf.SyncMessage.Request.Type; @@ -48,9 +44,7 @@ timestamp: Date.now(), reqestType: GROUPS, }); - await libsession - .getMessageQueue() - .sendUsingMultiDevice(currentPubKey, requestGroupSyncMessage); + await libsession.getMessageQueue().sendSyncMessage(requestGroupSyncMessage); this.timeout = setTimeout(this.onTimeout.bind(this), 60000); }