From 1238cbc4e61724cfd24017c97cb8bc704f29f7fd Mon Sep 17 00:00:00 2001 From: sachaaaaa Date: Wed, 23 Jan 2019 14:58:28 +1100 Subject: [PATCH 1/3] Send profile along with friend request accept message --- libloki/api.js | 32 +++----- libtextsecure/message_receiver.js | 117 +++++++++++++++++------------- 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/libloki/api.js b/libloki/api.js index 80dda5b6b..a83e90c8e 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -1,4 +1,4 @@ -/* global window, textsecure, log */ +/* global window, textsecure */ // eslint-disable-next-line func-names (function() { @@ -9,29 +9,19 @@ } async function sendEmptyMessage(pubKey) { - // empty content message - const content = new textsecure.protobuf.Content(); - - // will be called once the transmission succeeded or failed - const callback = res => { - if (res.errors.length > 0) { - res.errors.forEach(error => log.error(error)); - } else { - log.info('empty message sent successfully'); - } - }; const options = {}; - // send an empty message. The logic in ougoing_message will attach the prekeys. - const outgoingMessage = new textsecure.OutgoingMessage( - null, // server - Date.now(), // timestamp, - [pubKey], // numbers - content, // message - true, // silent - callback, // callback + // send an empty message. + // The logic downstream will attach the prekeys and our profile. + await textsecure.messaging.sendMessageToNumber( + pubKey, // number + null, // messageText + [], // attachments + null, // quote + Date.now(), // timestamp + null, // expireTimer + null, // profileKey options ); - await outgoingMessage.sendToNumber(pubKey); } window.libloki.api = { diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index dd01d2639..ade1ee659 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -909,56 +909,63 @@ MessageReceiver.prototype.extend({ p = this.handleEndSession(envelope.source); } return p.then(() => - this.processDecrypted(envelope, msg, envelope.source).then(message => { - const groupId = message.group && message.group.id; - const isBlocked = this.isGroupBlocked(groupId); - const isMe = envelope.source === textsecure.storage.user.getNumber(); - const conversation = window.ConversationController.get(envelope.source); - const isLeavingGroup = Boolean( - message.group && - message.group.type === textsecure.protobuf.GroupContext.Type.QUIT - ); - const friendRequest = - envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST; - - // Check if we need to update any profile names - if (!isMe && conversation) { - let profile = null; - if (message.profile) { - profile = JSON.parse(message.profile.encodeJSON()); + this.processDecrypted(envelope, msg, envelope.source).then( + async message => { + const groupId = message.group && message.group.id; + const isBlocked = this.isGroupBlocked(groupId); + const isMe = envelope.source === textsecure.storage.user.getNumber(); + const conversation = window.ConversationController.get( + envelope.source + ); + const isLeavingGroup = Boolean( + message.group && + message.group.type === textsecure.protobuf.GroupContext.Type.QUIT + ); + const friendRequest = + envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST; + + // Check if we need to update any profile names + if (!isMe && conversation) { + let profile = null; + if (message.profile) { + profile = JSON.parse(message.profile.encodeJSON()); + } + + // Update the conversation + await conversation.setProfile(profile); } - // Update the conversation - conversation.setProfile(profile); - } + if (friendRequest && isMe) { + window.log.info('refusing to add a friend request to ourselves'); + throw new Error('Cannot add a friend request for ourselves!'); + } - if (friendRequest && isMe) { - window.log.info('refusing to add a friend request to ourselves'); - throw new Error('Cannot add a friend request for ourselves!'); - } + if (groupId && isBlocked && !(isMe && isLeavingGroup)) { + window.log.warn( + `Message ${this.getEnvelopeId( + envelope + )} ignored; destined for blocked group` + ); + return this.removeFromCache(envelope); + } + if (!message.body) { + return null; + } - if (groupId && isBlocked && !(isMe && isLeavingGroup)) { - window.log.warn( - `Message ${this.getEnvelopeId( - envelope - )} ignored; destined for blocked group` - ); - return this.removeFromCache(envelope); + const ev = new Event('message'); + ev.confirm = this.removeFromCache.bind(this, envelope); + ev.data = { + friendRequest, + source: envelope.source, + sourceDevice: envelope.sourceDevice, + timestamp: envelope.timestamp.toNumber(), + receivedAt: envelope.receivedAt, + unidentifiedDeliveryReceived: envelope.unidentifiedDeliveryReceived, + message, + }; + return this.dispatchAndWait(ev); } - - const ev = new Event('message'); - ev.confirm = this.removeFromCache.bind(this, envelope); - ev.data = { - friendRequest, - source: envelope.source, - sourceDevice: envelope.sourceDevice, - timestamp: envelope.timestamp.toNumber(), - receivedAt: envelope.receivedAt, - unidentifiedDeliveryReceived: envelope.unidentifiedDeliveryReceived, - message, - }; - return this.dispatchAndWait(ev); - }) + ) ); }, handleLegacyMessage(envelope) { @@ -994,7 +1001,7 @@ MessageReceiver.prototype.extend({ if (content.syncMessage) return this.handleSyncMessage(envelope, content.syncMessage); if (content.dataMessage) - return this.handleDataMessage(envelope, content.dataMessage); + await this.handleDataMessage(envelope, content.dataMessage); if (content.nullMessage) return this.handleNullMessage(envelope, content.nullMessage); if (content.callMessage) @@ -1004,13 +1011,19 @@ MessageReceiver.prototype.extend({ if (content.typingMessage) return this.handleTypingMessage(envelope, content.typingMessage); - // Trigger conversation friend request event for empty message - const conversation = window.ConversationController.get(envelope.source); - if (conversation) { - conversation.onFriendRequestAccepted(); - conversation.notifyFriendRequest(envelope.source, 'accepted'); + // Trigger conversation friend request event + if ( + envelope.type === textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE && + (content.dataMessage === null || content.dataMessage.flags === null) + ) { + const conversation = window.ConversationController.get(envelope.source); + if (conversation) { + conversation.onFriendRequestAccepted(); + conversation.notifyFriendRequest(envelope.source, 'accepted'); + } + this.removeFromCache(envelope); } - this.removeFromCache(envelope); + return null; }, handleCallMessage(envelope) { From adfb4ab3719c87e7dc13efa71e26ca3b61942b2e Mon Sep 17 00:00:00 2001 From: sachaaaaa Date: Wed, 23 Jan 2019 15:57:56 +1100 Subject: [PATCH 2/3] work with session reset --- js/models/conversations.js | 2 ++ libloki/api.js | 53 +++++++++++++++++++++++-------- libtextsecure/message_receiver.js | 26 +++++++-------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 82035aef9..289b45697 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -653,7 +653,9 @@ await this.respondToAllPendingFriendRequests({ response: 'accepted', }); + return true; } + return false; }, async onFriendRequestTimeout() { // Unset the timer diff --git a/libloki/api.js b/libloki/api.js index a83e90c8e..6c5c8365f 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -1,27 +1,52 @@ -/* global window, textsecure */ +/* global window, textsecure, log */ // eslint-disable-next-line func-names (function() { window.libloki = window.libloki || {}; async function sendFriendRequestAccepted(pubKey) { - return sendEmptyMessage(pubKey); + return sendEmptyMessage(pubKey, true); } - async function sendEmptyMessage(pubKey) { + async function sendEmptyMessage(pubKey, sendContentMessage = false) { const options = {}; // send an empty message. - // The logic downstream will attach the prekeys and our profile. - await textsecure.messaging.sendMessageToNumber( - pubKey, // number - null, // messageText - [], // attachments - null, // quote - Date.now(), // timestamp - null, // expireTimer - null, // profileKey - options - ); + if (sendContentMessage) { + // The logic downstream will attach the prekeys and our profile. + await textsecure.messaging.sendMessageToNumber( + pubKey, // number + null, // messageText + [], // attachments + null, // quote + Date.now(), // timestamp + null, // expireTimer + null, // profileKey + options + ); + } else { + // empty content message + const content = new textsecure.protobuf.Content(); + + // will be called once the transmission succeeded or failed + const callback = res => { + if (res.errors.length > 0) { + res.errors.forEach(error => log.error(error)); + } else { + log.info('empty message sent successfully'); + } + }; + // send an empty message. The logic in ougoing_message will attach the prekeys. + const outgoingMessage = new textsecure.OutgoingMessage( + null, // server + Date.now(), // timestamp, + [pubKey], // numbers + content, // message + true, // silent + callback, // callback + options + ); + await outgoingMessage.sendToNumber(pubKey); + } } window.libloki.api = { diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index ade1ee659..313e6c430 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -948,8 +948,17 @@ MessageReceiver.prototype.extend({ ); return this.removeFromCache(envelope); } + if (!message.body) { - return null; + // Trigger conversation friend request event for empty message + if (conversation && !message.flags) { + const isFriendRequestAccept = await conversation.onFriendRequestAccepted(); + if (isFriendRequestAccept) { + await conversation.notifyFriendRequest(envelope.source, 'accepted'); + this.removeFromCache(envelope); + return null; + } + } } const ev = new Event('message'); @@ -1001,7 +1010,7 @@ MessageReceiver.prototype.extend({ if (content.syncMessage) return this.handleSyncMessage(envelope, content.syncMessage); if (content.dataMessage) - await this.handleDataMessage(envelope, content.dataMessage); + return this.handleDataMessage(envelope, content.dataMessage); if (content.nullMessage) return this.handleNullMessage(envelope, content.nullMessage); if (content.callMessage) @@ -1011,19 +1020,6 @@ MessageReceiver.prototype.extend({ if (content.typingMessage) return this.handleTypingMessage(envelope, content.typingMessage); - // Trigger conversation friend request event - if ( - envelope.type === textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE && - (content.dataMessage === null || content.dataMessage.flags === null) - ) { - const conversation = window.ConversationController.get(envelope.source); - if (conversation) { - conversation.onFriendRequestAccepted(); - conversation.notifyFriendRequest(envelope.source, 'accepted'); - } - this.removeFromCache(envelope); - } - return null; }, handleCallMessage(envelope) { From fe63a9af8cf69b580566ffa22ac711e6eb60903f Mon Sep 17 00:00:00 2001 From: sachaaaaa Date: Fri, 25 Jan 2019 11:17:24 +1100 Subject: [PATCH 3/3] always remove message from cache and return early when message.body is null --- libtextsecure/message_receiver.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 313e6c430..ec8f380e2 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -954,11 +954,14 @@ MessageReceiver.prototype.extend({ if (conversation && !message.flags) { const isFriendRequestAccept = await conversation.onFriendRequestAccepted(); if (isFriendRequestAccept) { - await conversation.notifyFriendRequest(envelope.source, 'accepted'); - this.removeFromCache(envelope); - return null; + await conversation.notifyFriendRequest( + envelope.source, + 'accepted' + ); } } + this.removeFromCache(envelope); + return null; } const ev = new Event('message');