From a497871ea33d2d75ad43a7648d2eeee9225b4db2 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 19 May 2020 11:08:38 +1000 Subject: [PATCH 1/4] Made changes for new protocol --- js/models/conversations.js | 3 +- js/models/messages.js | 19 +------- libloki/api.js | 21 +++++++++ libtextsecure/message_receiver.js | 78 +++++++++++++++++++------------ libtextsecure/sendmessage.js | 10 +++- 5 files changed, 82 insertions(+), 49 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 64f333019..eaf036605 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -795,8 +795,7 @@ const status = this.get('friendRequestStatus'); return ( status === FriendRequestStatusEnum.pendingSend || - status === FriendRequestStatusEnum.requestSent || - status === FriendRequestStatusEnum.requestExpired + status === FriendRequestStatusEnum.requestSent ); }, hasReceivedFriendRequest() { diff --git a/js/models/messages.js b/js/models/messages.js index 6025b3071..70f2f8b03 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -2045,23 +2045,8 @@ } if (message.isFriendRequest() && isSessionRequest) { - // Check if the contact is a member in one of our private groups: - const groupMember = window - .getConversations() - .models.filter(c => c.get('members')) - .reduce((acc, x) => window.Lodash.concat(acc, x.get('members')), []) - .includes(primarySource); - - if (groupMember) { - window.log.info( - `Auto accepting a 'group' friend request for a known group member: ${primarySource}` - ); - - window.libloki.api.sendBackgroundMessage(message.get('source')); - - confirm(); - } - + window.libloki.api.sendSessionEstablishedMessage(message.get('source')); + confirm(); // Wether or not we accepted the FR, we exit early so background friend requests // cannot be used for establishing regular private conversations return null; diff --git a/libloki/api.js b/libloki/api.js index 6456e2688..ad73318e4 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -4,6 +4,26 @@ (function() { window.libloki = window.libloki || {}; + async function sendSessionEstablishedMessage(pubKey) { + const nullMessage = new textsecure.protobuf.NullMessage(); + const content = new textsecure.protobuf.Content({ + nullMessage, + }); + + // The below message type will ignore auto FR + const options = { messageType: 'onlineBroadcast' }; + const outgoingMessage = new textsecure.OutgoingMessage( + null, // server + Date.now(), // timestamp, + [pubKey], // numbers + content, // message + true, // silent + () => null, // callback + options + ); + await outgoingMessage.sendToNumber(pubKey); + } + async function sendBackgroundMessage(pubKey) { return sendOnlineBroadcastMessage(pubKey); } @@ -273,6 +293,7 @@ } window.libloki.api = { + sendSessionEstablishedMessage, sendBackgroundMessage, sendOnlineBroadcastMessage, sendPairingAuthorisation, diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 01147ea74..deb8aa243 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -644,29 +644,6 @@ MessageReceiver.prototype.extend({ return null; } - let conversation; - try { - conversation = await window.ConversationController.getOrCreateAndWait( - envelope.source, - 'private' - ); - } catch (e) { - window.log.info('Error getting conversation: ', envelope.source); - } - - // Type here can actually be UNIDENTIFIED_SENDER even if - // the underlying message is FRIEND_REQUEST - if (envelope.type !== textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { - // If we got here there is a valid session, which meants friend request - // is complete (if it wasn't already) - if (conversation) { - const isFriendRequestAccept = await conversation.onFriendRequestAccepted(); - if (isFriendRequestAccept) { - await conversation.notifyFriendRequest(envelope.source, 'accepted'); - } - } - } - this.updateCache(envelope, plaintext).catch(error => { window.log.error( 'decrypt failed to save decrypted message contents to cache:', @@ -1313,13 +1290,11 @@ MessageReceiver.prototype.extend({ message.group && message.group.type === textsecure.protobuf.GroupContext.Type.QUIT ); - const friendRequest = - envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST; const { UNPAIRING_REQUEST } = textsecure.protobuf.DataMessage.Flags; // eslint-disable-next-line no-bitwise const isUnpairingRequest = Boolean(message.flags & UNPAIRING_REQUEST); - if (!friendRequest && isUnpairingRequest) { + if (isUnpairingRequest) { // TODO: move high-level pairing logic to libloki.multidevice.xx const unpairingRequestIsLegit = async () => { @@ -1394,7 +1369,7 @@ MessageReceiver.prototype.extend({ // if we're not friends with the current user that sent this private message // Check to see if we need to auto accept their friend request const isGroupMessage = !!groupId; - if (friendRequest || (!isGroupMessage && !conversation.isFriend())) { + if (!isGroupMessage && !conversation.isFriend()) { if (isMe) { window.log.info('refusing to add a friend request to ourselves'); throw new Error('Cannot add a friend request for ourselves!'); @@ -1429,16 +1404,27 @@ MessageReceiver.prototype.extend({ ); return this.removeFromCache(envelope); } - if (!friendRequest && this.isMessageEmpty(message)) { + if (this.isMessageEmpty(message)) { window.log.warn( `Message ${this.getEnvelopeId(envelope)} ignored; it was empty` ); return this.removeFromCache(envelope); } + + // Loki - Temp hack until new protocol + // A friend request is a non-group text message + const friendRequestStatus = conversation.get('friendRequestStatus'); + const FriendRequestStatusEnum = window.friends.friendRequestStatusEnum; + const isFriendRequestStatusNone = + friendRequestStatus === FriendRequestStatusEnum.none || + friendRequestStatus === FriendRequestStatusEnum.requestExpired; + const isFriendRequest = + !isGroupMessage && isFriendRequestStatusNone && !_.isEmpty(message.body); + const ev = new Event('message'); ev.confirm = this.removeFromCache.bind(this, envelope); ev.data = { - friendRequest, + friendRequest: isFriendRequest, source: envelope.source, sourceDevice: envelope.sourceDevice, timestamp: envelope.timestamp.toNumber(), @@ -1493,6 +1479,31 @@ MessageReceiver.prototype.extend({ } return this.innerHandleContentMessage(envelope, plaintext); }, + async handleFriendRequestAcceptIfNeeded(envelope, content) { + const isGroupMessage = + content && + content.dataMessage && + (content.dataMessage.group || content.dataMessage.mediumGroupUpdate); + const isReceiptMessage = content && content.receiptMessage; + const isTypingMessage = content && content.typingMessage; + if (isGroupMessage || isReceiptMessage || isTypingMessage) { + return; + } + + // If we sent a friend request and got another message back then we should become friends + try { + const conversation = await window.ConversationController.getOrCreateAndWait( + envelope.source, + 'private' + ); + const isFriendRequestAccept = await conversation.onFriendRequestAccepted(); + if (isFriendRequestAccept) { + await conversation.notifyFriendRequest(envelope.source, 'accepted'); + } + } catch (e) { + window.log.info('Error getting conversation: ', envelope.source); + } + }, async innerHandleContentMessage(envelope, plaintext) { const content = textsecure.protobuf.Content.decode(plaintext); @@ -1503,6 +1514,8 @@ MessageReceiver.prototype.extend({ ); } + this.handleFriendRequestAcceptIfNeeded(envelope, content); + if (content.lokiAddressMessage) { return this.handleLokiAddressMessage( envelope, @@ -1606,6 +1619,13 @@ MessageReceiver.prototype.extend({ return this.dispatchEvent(ev); }, handleNullMessage(envelope) { + // Loki - Temp hack for new protocl backward compatibility + // This should be removed once we add the new protocol + if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { + window.log.info('sent session established to', envelope.source); + window.libloki.api.sendSessionEstablishedMessage(envelope.source); + } + window.log.info('null message from', this.getEnvelopeId(envelope)); this.removeFromCache(envelope); }, diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index da725272c..019bd9756 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -1096,6 +1096,14 @@ MessageSender.prototype = { window.log.error(prefix, error && error.stack ? error.stack : error); throw error; }; + + // Loki - Temp hack for new protocol + // A session reset should be a `FRIEND_REQUEST` + const msgOptions = { + messageType: 'friend-request', + ...options, + }; + // The actual deletion of the session now happens later // as we need to ensure the other contact has successfully // switch to a new session first. @@ -1104,7 +1112,7 @@ MessageSender.prototype = { proto, timestamp, silent, - options + msgOptions ).catch(logError('resetSession/sendToContact error:')); }, From e666c3c97d2e9af6e8e9f8bd58e5deb60b1583c2 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 19 May 2020 13:47:34 +1000 Subject: [PATCH 2/4] Add comments --- js/models/messages.js | 1 + libtextsecure/message_receiver.js | 1 + 2 files changed, 2 insertions(+) diff --git a/js/models/messages.js b/js/models/messages.js index 70f2f8b03..d3ea3b4e4 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -2045,6 +2045,7 @@ } if (message.isFriendRequest() && isSessionRequest) { + // We don't need to await the call below because we just want to send it off window.libloki.api.sendSessionEstablishedMessage(message.get('source')); confirm(); // Wether or not we accepted the FR, we exit early so background friend requests diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index deb8aa243..3192a31c6 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1623,6 +1623,7 @@ MessageReceiver.prototype.extend({ // This should be removed once we add the new protocol if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { window.log.info('sent session established to', envelope.source); + // We don't need to await the call below because we just want to send it off window.libloki.api.sendSessionEstablishedMessage(envelope.source); } From 3dc8ba2f022969f755669e385c8a6f1705ab703a Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 20 May 2020 09:08:34 +1000 Subject: [PATCH 3/4] Minor fix --- libtextsecure/message_receiver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 1b40a1e5c..de913df47 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1302,7 +1302,7 @@ MessageReceiver.prototype.extend({ const isGroupMessage = Boolean(message.group || message.mediumGroupUpdate); const friendRequestStatusNoneOrExpired = conversation ? conversation.isFriendRequestStatusNoneOrExpired() - : false; + : true; const isFriendRequest = !isGroupMessage && !_.isEmpty(message.body) && From ec3132afc9c5a64479bf20069d16dde6a2e4cfea Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 21 May 2020 09:10:52 +1000 Subject: [PATCH 4/4] Fix auto accepting friend requests --- js/models/messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/models/messages.js b/js/models/messages.js index db074fc42..bb81814d0 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1941,7 +1941,7 @@ const { primaryDevicePubKey } = authorisation; // ensure the primary device is a friend const c = window.ConversationController.get(primaryDevicePubKey); - if (!c || !c.isFriendWithAnyDevice()) { + if (!c || !await c.isFriendWithAnyDevice()) { return false; } await libloki.storage.savePairingAuthorisation(authorisation);