diff --git a/js/models/messages.js b/js/models/messages.js index 5ea8fd8e9..d2e1cd87e 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -12,6 +12,7 @@ Whisper, clipboard, libloki, + lokiFileServerAPI, */ /* eslint-disable more/no-then */ @@ -444,6 +445,8 @@ await window.Signal.Data.saveMessage(this.attributes, { Message: Whisper.Message, }); + const pubKey = this.get('conversationId'); + await libloki.storage.saveAllPairingAuthorisationsFor(pubKey); conversation.onAcceptFriendRequest(); }, async declineFriendRequest() { diff --git a/js/modules/data.js b/js/modules/data.js index 8ce492924..d56b3cbf3 100644 --- a/js/modules/data.js +++ b/js/modules/data.js @@ -594,6 +594,9 @@ function signatureToBase64(signature) { return dcodeIO.ByteBuffer.wrap(signature).toString('base64'); } else if (isArrayBuffer(signature)) { return arrayBufferToBase64(signature); + } else if (typeof signature === 'string') { + // assume it's already base64 + return signature; } throw new Error( 'Invalid signature provided in createOrUpdatePairingAuthorisation. Needs to be either ArrayBuffer or ByteBuffer.' diff --git a/js/modules/loki_file_server_api.js b/js/modules/loki_file_server_api.js index 7f8b671da..3378df89e 100644 --- a/js/modules/loki_file_server_api.js +++ b/js/modules/loki_file_server_api.js @@ -19,9 +19,10 @@ class LokiFileServerAPI { async getUserDeviceMapping(pubKey) { const annotations = await this._server.getUserAnnotations(pubKey); - return annotations.find( + const deviceMapping = annotations.find( annotation => annotation.type === DEVICE_MAPPING_ANNOTATION_KEY ); + return deviceMapping ? deviceMapping.value : null; } async updateOurDeviceMapping() { diff --git a/libloki/crypto.js b/libloki/crypto.js index 7ee0282cc..a1f85d113 100644 --- a/libloki/crypto.js +++ b/libloki/crypto.js @@ -176,7 +176,6 @@ async function validateAuthorisation(authorisation) { const { - type, primaryDevicePubKey, secondaryDevicePubKey, requestSignature, @@ -184,10 +183,8 @@ } = authorisation; const alreadySecondaryDevice = !!window.storage.get('isSecondaryDevice'); const ourPubKey = textsecure.storage.user.getNumber(); - const isRequest = - type === textsecure.protobuf.PairingAuthorisationMessage.Type.REQUEST; - const isGrant = - type === textsecure.protobuf.PairingAuthorisationMessage.Type.GRANT; + const isRequest = !grantSignature; + const isGrant = !!grantSignature; if (!primaryDevicePubKey || !secondaryDevicePubKey) { window.log.warn( 'Received a pairing request with missing pubkeys. Ignored.' @@ -212,11 +209,18 @@ window.log.warn('Received a pairing request from ourselves. Ignored.'); return false; } - try { + const verify = async (signature, signatureType) => { + const encoding = typeof signature === 'string' ? 'base64' : undefined; await this.verifyPairingSignature( primaryDevicePubKey, secondaryDevicePubKey, - dcodeIO.ByteBuffer.wrap(requestSignature).toArrayBuffer(), + dcodeIO.ByteBuffer.wrap(signature, encoding).toArrayBuffer(), + signatureType + ); + }; + try { + await verify( + requestSignature, textsecure.protobuf.PairingAuthorisationMessage.Type.REQUEST ); } catch (e) { @@ -228,10 +232,8 @@ } if (isGrant) { try { - await this.verifyPairingSignature( - primaryDevicePubKey, - secondaryDevicePubKey, - dcodeIO.ByteBuffer.wrap(grantSignature).toArrayBuffer(), + await verify( + grantSignature, textsecure.protobuf.PairingAuthorisationMessage.Type.GRANT ); } catch (e) { diff --git a/libloki/storage.js b/libloki/storage.js index 25237cd02..aea53b4b7 100644 --- a/libloki/storage.js +++ b/libloki/storage.js @@ -1,4 +1,4 @@ -/* global window, libsignal, textsecure, Signal */ +/* global window, libsignal, textsecure, Signal, lokiFileServerAPI */ // eslint-disable-next-line func-names (function() { @@ -113,6 +113,33 @@ } } + // fetches device mappings from server. + // if the device is a secondary device, + // fetch the device mappings for its primary device + async function saveAllPairingAuthorisationsFor(pubKey) { + const deviceMapping = await lokiFileServerAPI.getUserDeviceMapping(pubKey); + let { authorisations } = deviceMapping || {}; + if (deviceMapping) { + if (deviceMapping.isPrimary !== '1') { + const { primaryDevicePubKey } = + authorisations.find( + authorisation => authorisation.secondaryDevicePubKey === pubKey + ) || {}; + if (primaryDevicePubKey) { + ({ authorisations } = + (await lokiFileServerAPI.getUserDeviceMapping( + primaryDevicePubKey + )) || {}); + } + await Promise.all( + authorisations.map(authorisation => + savePairingAuthorisation(authorisation) + ) + ); + } + } + } + function savePairingAuthorisation(authorisation) { return window.Signal.Data.createOrUpdatePairingAuthorisation(authorisation); } @@ -177,6 +204,7 @@ removeContactPreKeyBundle, verifyFriendRequestAcceptPreKey, savePairingAuthorisation, + saveAllPairingAuthorisationsFor, removePairingAuthorisationForSecondaryPubKey, getGrantAuthorisationForSecondaryPubKey, getAuthorisationForSecondaryPubKey,