diff --git a/lib/handlers/peer-to-peer-message-handler.js b/lib/handlers/peer-to-peer-message-handler.js --- a/lib/handlers/peer-to-peer-message-handler.js +++ b/lib/handlers/peer-to-peer-message-handler.js @@ -9,7 +9,8 @@ type PeerToPeerMessage, } from '../types/tunnelbroker/peer-to-peer-message-types.js'; import { getConfig } from '../utils/config.js'; -import { olmSessionErrors } from '../utils/olm-utils.js'; +import { getContentSigningKey } from '../utils/crypto-utils.js'; +import { hasHigherDeviceID, olmSessionErrors } from '../utils/olm-utils.js'; async function peerToPeerMessageHandler( message: PeerToPeerMessage, @@ -19,17 +20,25 @@ if (message.type === peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION) { const { senderInfo, encryptedData, sessionVersion } = message; const { userID: senderUserID, deviceID: senderDeviceID } = senderInfo; + + let deviceKeys: ?DeviceOlmInboundKeys = null; try { const { keys } = await identityClient.getInboundKeysForUser(senderUserID); + deviceKeys = keys[senderDeviceID]; + } catch (e) { + console.log(e.message); + } - const deviceKeys: ?DeviceOlmInboundKeys = keys[senderDeviceID]; - if (!deviceKeys) { - throw new Error( - 'No keys for the device that requested creating a session, ' + - `deviceID: ${senderDeviceID}`, - ); - } + if (!deviceKeys) { + console.log( + 'Error creating inbound session with device ' + + `${senderDeviceID}: No keys for the device, ` + + `session version: ${sessionVersion}`, + ); + return; + } + try { await olmAPI.initializeCryptoAccount(); const result = await olmAPI.contentInboundSessionCreator( deviceKeys.identityKeysBlob.primaryIdentityPublicKeys, @@ -49,10 +58,28 @@ `${senderDeviceID}, session version: ${sessionVersion}`, ); } else if (e.message?.includes(olmSessionErrors.raceCondition)) { - console.log( - 'Race condition while creating session with ' + - `${senderDeviceID}, session version: ${sessionVersion}`, - ); + const currentDeviceID = await getContentSigningKey(); + if (hasHigherDeviceID(currentDeviceID, senderDeviceID)) { + console.log( + 'Race condition while creating session with ' + + `${senderDeviceID}, session version: ${sessionVersion}, ` + + `this device has a higher deviceID and the session will be kept`, + ); + } else { + const result = await olmAPI.contentInboundSessionCreator( + deviceKeys.identityKeysBlob.primaryIdentityPublicKeys, + encryptedData, + sessionVersion, + true, + ); + console.log( + 'Overwrite session with device ' + + `${senderDeviceID}: ${result}, ` + + `session version: ${sessionVersion}`, + ); + // Resend all not-yet confirmed messages that were encrypted + // with overwrite session. Tracked in ENG-6982. + } } else { console.log( 'Error creating inbound session with device ' + diff --git a/lib/utils/olm-utils.js b/lib/utils/olm-utils.js --- a/lib/utils/olm-utils.js +++ b/lib/utils/olm-utils.js @@ -125,6 +125,17 @@ alreadyCreated: 'OLM_SESSION_ALREADY_CREATED', }); +function hasHigherDeviceID( + currenDeviceID: string, + otherDeviceID: string, +): boolean { + const compareResult = currenDeviceID.localeCompare(otherDeviceID); + if (compareResult === 0) { + throw new Error('Comparing the same deviceIDs'); + } + return compareResult === 1; +} + export { retrieveAccountKeysSet, getAccountPrekeysSet, @@ -132,5 +143,6 @@ shouldRotatePrekey, getAccountOneTimeKeys, retrieveIdentityKeysAndPrekeys, + hasHigherDeviceID, olmSessionErrors, };