From d9c521b09d1e9f5354e1d121dc3b133f91914caf Mon Sep 17 00:00:00 2001 From: Mikunj Varsani Date: Mon, 10 Feb 2020 18:57:00 +1100 Subject: [PATCH] Fix message syncing in closed groups --- README.md | 3 ++- js/models/messages.js | 16 +++++++++++----- js/modules/loki_app_dot_net_api.js | 5 ++++- libtextsecure/sendmessage.js | 27 ++++++++++++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 84cde08ec..ce39ccced 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ [![Build Status](https://travis-ci.org/loki-project/loki-messenger.svg?branch=development)](https://travis-ci.org/loki-project/loki-messenger) Session allows for truly decentralized, end to end, and private encrypted chats. Session is built to handle both online and fully Asynchronous offline messages. Session implements the Signal protocol for message encryption. Our Client interface is a fork of [Signal Messenger](https://signal.org/). + ## Summary -Session integrates directly with Loki [Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users IP Addresses. For a full understanding of how Session works, read the [Loki whitepaper](https://loki.network/whitepaper). +Session integrates directly with Loki [Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users IP Addresses. For a full understanding of how Session works, read the [Loki whitepaper](https://loki.network/whitepaper). **Offline messages** diff --git a/js/models/messages.js b/js/models/messages.js index 0fb0a6e61..12339ac2b 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1898,6 +1898,8 @@ const authorisation = await libloki.storage.getGrantAuthorisationForSecondaryPubKey( source ); + const primarySource = + (authorisation && authorisation.primaryDevicePubKey) || source; const isGroupMessage = !!initialMessage.group; if (isGroupMessage) { conversationId = initialMessage.group.id; @@ -1916,10 +1918,12 @@ const knownMembers = conversation.get('members'); if (!newGroup && knownMembers) { - const fromMember = knownMembers.includes(source); + const fromMember = knownMembers.includes(primarySource); if (!fromMember) { - window.log.warn(`Ignoring group message from non-member: ${source}`); + window.log.warn( + `Ignoring group message from non-member: ${primarySource}` + ); confirm(); return null; } @@ -1938,7 +1942,9 @@ ); } - const fromAdmin = conversation.get('groupAdmins').includes(source); + const fromAdmin = conversation + .get('groupAdmins') + .includes(primarySource); if (!fromAdmin) { // Make sure the message is not removing members / renaming the group @@ -2016,11 +2022,11 @@ .getConversations() .models.filter(c => c.get('members')) .reduce((acc, x) => window.Lodash.concat(acc, x.get('members')), []) - .includes(source); + .includes(primarySource); if (groupMember) { window.log.info( - `Auto accepting a 'group' friend request for a known group member: ${groupMember}` + `Auto accepting a 'group' friend request for a known group member: ${primarySource}` ); window.libloki.api.sendBackgroundMessage(message.get('source')); diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index fab433da6..c1a182ae1 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -487,7 +487,10 @@ class LokiAppDotNetServerAPI { try { response = options.textResponse ? respStr : JSON.parse(respStr); } catch (e) { - log.warn(`_sendToProxy Could not parse inner JSON [${respStr}]`, endpoint); + log.warn( + `_sendToProxy Could not parse inner JSON [${respStr}]`, + endpoint + ); } } else { log.warn( diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index d59a06d0f..e4cea3e27 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -873,7 +873,14 @@ MessageSender.prototype = { }, sendGroupProto(providedNumbers, proto, timestamp = Date.now(), options = {}) { - if (providedNumbers.length === 0) { + // 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: [], @@ -883,7 +890,7 @@ MessageSender.prototype = { }); } - return new Promise((resolve, reject) => { + const sendPromise = new Promise((resolve, reject) => { const silent = true; const callback = res => { res.dataMessage = proto.toArrayBuffer(); @@ -896,13 +903,20 @@ MessageSender.prototype = { this.sendMessageProto( timestamp, - providedNumbers, + numbers, proto, callback, silent, options ); }); + + return sendPromise.then(result => { + // Sync the group message to our other devices + const encoded = textsecure.protobuf.DataMessage.encode(proto); + this.sendSyncMessage(encoded, timestamp, null, null, [], [], options); + return result; + }); }, async getMessageProto( @@ -1087,8 +1101,11 @@ MessageSender.prototype = { profileKey, options ) { - const me = textsecure.storage.user.getNumber(); - let numbers = groupNumbers.filter(number => number !== me); + // 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]; }