diff --git a/libloki/api.js b/libloki/api.js index ef1baccf4..b18746ef8 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -193,6 +193,29 @@ }); return syncMessage; } + function createOpenGroupsSyncProtoMessage(conversations) { + // We only want to sync across open groups that we haven't left + const sessionOpenGroups = conversations.filter( + c => c.isPublic() && !c.isRss() && !c.get('left') + ); + + if (sessionOpenGroups.length === 0) { + return null; + } + + const openGroups = sessionOpenGroups.map( + conversation => + new textsecure.protobuf.SyncMessage.OpenGroupDetails({ + url: conversation.id.split('@').pop(), + channelId: conversation.get('channelId'), + }) + ); + + const syncMessage = new textsecure.protobuf.SyncMessage({ + openGroups, + }); + return syncMessage; + } async function sendPairingAuthorisation(authorisation, recipientPubKey) { const pairingAuthorisation = createPairingAuthorisationProtoMessage( authorisation @@ -257,5 +280,6 @@ sendUnpairingMessageToSecondary, createContactSyncProtoMessage, createGroupSyncProtoMessage, + createOpenGroupsSyncProtoMessage, }; })(); diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js index 088422630..b26ceda99 100644 --- a/libtextsecure/account_manager.js +++ b/libtextsecure/account_manager.js @@ -638,6 +638,7 @@ const conversations = window.getConversations().models; textsecure.messaging.sendContactSyncMessage(conversations); textsecure.messaging.sendGroupSyncMessage(conversations); + textsecure.messaging.sendOpenGroupsSyncMessage(conversations); }, validatePubKeyHex(pubKey) { const c = new Whisper.Conversation({ diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 81adb351f..8397df5f8 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1505,6 +1505,8 @@ MessageReceiver.prototype.extend({ return this.handleContacts(envelope, syncMessage.contacts); } else if (syncMessage.groups) { return this.handleGroups(envelope, syncMessage.groups); + } else if (syncMessage.openGroups) { + return this.handleOpenGroups(envelope, syncMessage.openGroups); } else if (syncMessage.blocked) { return this.handleBlocked(envelope, syncMessage.blocked); } else if (syncMessage.request) { @@ -1606,6 +1608,12 @@ MessageReceiver.prototype.extend({ }); }); }, + handleOpenGroups(envelope, openGroups) { + openGroups.forEach(({ url, channelId }) => { + window.attemptConnection(url, channelId); + }); + return this.removeFromCache(envelope); + }, handleBlocked(envelope, blocked) { window.log.info('Setting these numbers as blocked:', blocked.numbers); textsecure.storage.put('blocked', blocked.numbers); diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 3d39d472d..8775c9987 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -727,6 +727,38 @@ MessageSender.prototype = { return Promise.all(syncPromises); }, + sendOpenGroupsSyncMessage(conversations) { + // If we havn't got a primaryDeviceKey then we are in the middle of pairing + // primaryDevicePubKey is set to our own number if we are the master device + const primaryDeviceKey = window.storage.get('primaryDevicePubKey'); + if (!primaryDeviceKey) { + return Promise.resolve(); + } + + // Send the whole list of open groups in a single message + + const openGroupsSyncMessage = libloki.api.createOpenGroupsSyncProtoMessage( + conversations + ); + + if (!openGroupsSyncMessage) { + window.log.info('No open groups to sync'); + return Promise.resolve(); + } + + const contentMessage = new textsecure.protobuf.Content(); + contentMessage.syncMessage = openGroupsSyncMessage; + + const silent = true; + return this.sendIndividualProto( + primaryDeviceKey, + contentMessage, + Date.now(), + silent, + {} // options + ); + }, + sendRequestContactSyncMessage(options) { const myNumber = textsecure.storage.user.getNumber(); const myDevice = textsecure.storage.user.getDeviceId(); @@ -1287,6 +1319,9 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { ); this.sendContactSyncMessage = sender.sendContactSyncMessage.bind(sender); this.sendGroupSyncMessage = sender.sendGroupSyncMessage.bind(sender); + this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( + sender + ); this.sendRequestConfigurationSyncMessage = sender.sendRequestConfigurationSyncMessage.bind( sender ); diff --git a/protos/SignalService.proto b/protos/SignalService.proto index f383448fe..e8f96edfe 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -314,15 +314,21 @@ message SyncMessage { optional bool linkPreviews = 4; } - optional Sent sent = 1; - optional Contacts contacts = 2; - optional Groups groups = 3; - optional Request request = 4; - repeated Read read = 5; - optional Blocked blocked = 6; - optional Verified verified = 7; - optional Configuration configuration = 9; - optional bytes padding = 8; + message OpenGroupDetails { + optional string url = 1; + optional uint32 channelId = 2; + } + + optional Sent sent = 1; + optional Contacts contacts = 2; + optional Groups groups = 3; + optional Request request = 4; + repeated Read read = 5; + optional Blocked blocked = 6; + optional Verified verified = 7; + optional Configuration configuration = 9; + optional bytes padding = 8; + repeated OpenGroupDetails openGroups = 100; } message AttachmentPointer {