From 05e682cdc2d795c9fd8cb093610c1125197f5e0c Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 5 Oct 2020 10:53:09 +1100 Subject: [PATCH 1/4] enable back swarm polling when we get added back to a group --- ts/receiver/mediumGroups.ts | 5 +++-- ts/session/snode_api/swarmPolling.ts | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ts/receiver/mediumGroups.ts b/ts/receiver/mediumGroups.ts index a0fe3eb75..7c9582b3a 100644 --- a/ts/receiver/mediumGroups.ts +++ b/ts/receiver/mediumGroups.ts @@ -331,6 +331,8 @@ async function handleMediumGroupChange( // Enable typing: maybeConvo.set('isKickedFromGroup', false); maybeConvo.set('left', false); + // Subscribe to this group id + window.SwarmPolling.addGroupId(new PubKey(groupId)); maybeConvo.updateTextInputState(); } } @@ -342,8 +344,7 @@ async function handleMediumGroupChange( const userSenderKey = await createSenderKeyForGroup(groupId, primary); window.log.warn( 'Sharing our new senderKey with remainingMembers via message', - members, - userSenderKey + members ); await shareSenderKeys(groupId, members, userSenderKey); diff --git a/ts/session/snode_api/swarmPolling.ts b/ts/session/snode_api/swarmPolling.ts index ac2eaacc7..0f3407c27 100644 --- a/ts/session/snode_api/swarmPolling.ts +++ b/ts/session/snode_api/swarmPolling.ts @@ -51,12 +51,16 @@ export class SwarmPolling { } public addGroupId(pubkey: PubKey) { - this.groupPubkeys.push(pubkey); + if (this.groupPubkeys.findIndex(m => m.key === pubkey.key) === -1) { + this.groupPubkeys.push(pubkey); + } } public addPubkey(pk: PubKey | string) { const pubkey = PubKey.cast(pk); - this.pubkeys.push(pubkey); + if (this.pubkeys.findIndex(m => m.key === pubkey.key) === -1) { + this.pubkeys.push(pubkey); + } } public removePubkey(pk: PubKey | string) { From c0497e3df179dedbf25420893ddc3fe98eb52853 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 5 Oct 2020 11:16:13 +1100 Subject: [PATCH 2/4] trigger senderKeyRequest if we get a DOMException on decryptGCM() --- ts/session/medium_group/ratchet.ts | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/ts/session/medium_group/ratchet.ts b/ts/session/medium_group/ratchet.ts index 4b3c35dbd..5808ad4bf 100644 --- a/ts/session/medium_group/ratchet.ts +++ b/ts/session/medium_group/ratchet.ts @@ -2,6 +2,8 @@ import { PubKey } from '../types'; import * as Data from '../../../js/modules/data'; import { saveSenderKeysInner } from './index'; import { StringUtils } from '../utils'; +import { MediumGroupRequestKeysMessage } from '../messages/outgoing'; +import { getMessageQueue } from '..'; const toHex = (buffer: ArrayBuffer) => StringUtils.decode(buffer, 'hex'); const fromHex = (hex: string) => StringUtils.encode(hex, 'hex'); @@ -269,11 +271,24 @@ async function decryptWithSenderKeyInner( return null; } - // TODO: this might fail, handle this - const plaintext = await window.libloki.crypto.DecryptGCM( - messageKey, - ciphertext - ); + try { + const plaintext = await window.libloki.crypto.DecryptGCM( + messageKey, + ciphertext + ); + return plaintext; + } catch (e) { + window.log.error('Got error during DecryptGCM():', e); + if (e instanceof DOMException) { + const params = { + timestamp: Date.now(), + groupId, + }; + // we consider we don't have the correct key for this sender, so request the latest one + const requestKeysMessage = new MediumGroupRequestKeysMessage(params); + const sender = new PubKey(senderIdentity); + await getMessageQueue().send(sender, requestKeysMessage); + } + } - return plaintext; } From 97eaf680859a072fb9c2f7ad77368b5c2653ce04 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 5 Oct 2020 11:29:02 +1100 Subject: [PATCH 3/4] clean getExistingSenderKeysForGroup as we don't need the diff anymore --- ts/session/medium_group/index.ts | 18 +++--------------- ts/session/medium_group/ratchet.ts | 1 - 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/ts/session/medium_group/index.ts b/ts/session/medium_group/index.ts index ac00cfc7b..4949066a4 100644 --- a/ts/session/medium_group/index.ts +++ b/ts/session/medium_group/index.ts @@ -269,26 +269,14 @@ async function getExistingSenderKeysForGroup( // as they each member need to regenerate a new senderkey async function getOrUpdateSenderKeysForJoiningMembers( groupId: string, - members: Array, - diff?: GroupDiff, - joiningMembersSenderKeys?: Array + members: Array ): Promise> { - const leavingMembers = diff?.leavingMembers || []; - const joiningMembers = diff?.joiningMembers || []; - - const existingMembers = _.difference(members, joiningMembers); // get all devices for members const allDevices = _.flatten( - await Promise.all( - existingMembers.map(m => MultiDeviceProtocol.getAllDevices(m)) - ) + await Promise.all(members.map(m => MultiDeviceProtocol.getAllDevices(m))) ); - let existingKeys: Array = []; - if (leavingMembers.length === 0) { - existingKeys = await getExistingSenderKeysForGroup(groupId, allDevices); - } - return _.union(joiningMembersSenderKeys, existingKeys); + return getExistingSenderKeysForGroup(groupId, allDevices); } async function getGroupSecretKey(groupId: string): Promise { diff --git a/ts/session/medium_group/ratchet.ts b/ts/session/medium_group/ratchet.ts index 5808ad4bf..5f9d81db9 100644 --- a/ts/session/medium_group/ratchet.ts +++ b/ts/session/medium_group/ratchet.ts @@ -290,5 +290,4 @@ async function decryptWithSenderKeyInner( await getMessageQueue().send(sender, requestKeysMessage); } } - } From 2f8f79c5d284d36ab99dfce870a7f94bd9764e47 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 5 Oct 2020 12:31:07 +1100 Subject: [PATCH 4/4] make message clearer when we try to reuse a keyIdx in the ratchet --- ts/receiver/contentMessage.ts | 6 +----- ts/session/medium_group/ratchet.ts | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index 5a6a61ca4..bb6fec351 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -287,11 +287,7 @@ async function decrypt( return plaintext; } catch (error) { - if ( - error && - (error instanceof textsecure.SenderKeyMissing || - error instanceof DOMException) - ) { + if (error && error instanceof textsecure.SenderKeyMissing) { const groupId = envelope.source; const { senderIdentity } = error; if (senderIdentity) { diff --git a/ts/session/medium_group/ratchet.ts b/ts/session/medium_group/ratchet.ts index 5f9d81db9..2c3180fa7 100644 --- a/ts/session/medium_group/ratchet.ts +++ b/ts/session/medium_group/ratchet.ts @@ -204,6 +204,11 @@ async function advanceRatchet( log.error('[idx] not found key for idx: ', idx); // I probably want a better error handling than this return null; + } else if (idx === ratchet.keyIdx) { + log.error( + `advanceRatchet() called with idx:${idx}, current ratchetIdx:${ratchet.keyIdx}. We already burnt that keyIdx before.` + ); + return null; } const { messageKeys } = ratchet; @@ -278,16 +283,12 @@ async function decryptWithSenderKeyInner( ); return plaintext; } catch (e) { - window.log.error('Got error during DecryptGCM():', e); + window.log.error('Got error during DecryptGCM()', e); if (e instanceof DOMException) { - const params = { - timestamp: Date.now(), - groupId, - }; - // we consider we don't have the correct key for this sender, so request the latest one - const requestKeysMessage = new MediumGroupRequestKeysMessage(params); - const sender = new PubKey(senderIdentity); - await getMessageQueue().send(sender, requestKeysMessage); + window.log.error( + 'Got DOMException during DecryptGCM(). Rethrowing as SenderKeyMissing ' + ); + throw new window.textsecure.SenderKeyMissing(senderIdentity); } } }