diff --git a/js/views/standalone_registration_view.js b/js/views/standalone_registration_view.js index 6d2734a7a..4ea51f500 100644 --- a/js/views/standalone_registration_view.js +++ b/js/views/standalone_registration_view.js @@ -1,4 +1,11 @@ -/* global Whisper, $, getAccountManager, textsecure, i18n, passwordUtil, _ */ +/* global Whisper, + $, + getAccountManager, + textsecure, + i18n, + passwordUtil, + _, + lokiFileServerAPI */ /* eslint-disable more/no-then */ @@ -137,8 +144,9 @@ const language = this.$('#mnemonic-display-language').val(); this.showProfilePage(mnemonic, language); }, - onSecondaryDeviceRegistered() { + async onSecondaryDeviceRegistered() { clearInterval(this.pairingInterval); + await lokiFileServerAPI.updateOurDeviceMapping(); // Ensure the left menu is updated Whisper.events.trigger('userChanged', { isSecondaryDevice: true }); this.$el.trigger('openInbox'); diff --git a/libloki/crypto.js b/libloki/crypto.js index bf0f9b77f..7ee0282cc 100644 --- a/libloki/crypto.js +++ b/libloki/crypto.js @@ -174,7 +174,78 @@ return signature; } - async function verifyPairingAuthorisation( + async function validateAuthorisation(authorisation) { + const { + type, + primaryDevicePubKey, + secondaryDevicePubKey, + requestSignature, + grantSignature, + } = 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; + if (!primaryDevicePubKey || !secondaryDevicePubKey) { + window.log.warn( + 'Received a pairing request with missing pubkeys. Ignored.' + ); + return false; + } else if (!requestSignature) { + window.log.warn( + 'Received a pairing request with missing request signature. Ignored.' + ); + return false; + } else if (isRequest && alreadySecondaryDevice) { + window.log.warn( + 'Received a pairing request while being a secondary device. Ignored.' + ); + return false; + } else if (isRequest && authorisation.primaryDevicePubKey !== ourPubKey) { + window.log.warn( + 'Received a pairing request addressed to another pubkey. Ignored.' + ); + return false; + } else if (isRequest && authorisation.secondaryDevicePubKey === ourPubKey) { + window.log.warn('Received a pairing request from ourselves. Ignored.'); + return false; + } + try { + await this.verifyPairingSignature( + primaryDevicePubKey, + secondaryDevicePubKey, + dcodeIO.ByteBuffer.wrap(requestSignature).toArrayBuffer(), + textsecure.protobuf.PairingAuthorisationMessage.Type.REQUEST + ); + } catch (e) { + window.log.warn( + 'Could not verify pairing request authorisation signature. Ignoring message.' + ); + window.log.error(e); + return false; + } + if (isGrant) { + try { + await this.verifyPairingSignature( + primaryDevicePubKey, + secondaryDevicePubKey, + dcodeIO.ByteBuffer.wrap(grantSignature).toArrayBuffer(), + textsecure.protobuf.PairingAuthorisationMessage.Type.GRANT + ); + } catch (e) { + window.log.warn( + 'Could not verify pairing grant authorisation signature. Ignoring message.' + ); + window.log.error(e); + return false; + } + } + return true; + } + + async function verifyPairingSignature( primaryDevicePubKey, secondaryPubKey, signature, @@ -233,7 +304,8 @@ snodeCipher, decryptToken, generateSignatureForPairing, - verifyPairingAuthorisation, + verifyPairingSignature, + validateAuthorisation, // for testing _LokiSnodeChannel: LokiSnodeChannel, _decodeSnodeAddressToPubKey: decodeSnodeAddressToPubKey, diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js index 4835e8711..73b458f02 100644 --- a/libtextsecure/account_manager.js +++ b/libtextsecure/account_manager.js @@ -3,6 +3,7 @@ textsecure, libsignal, libloki, + lokiFileServerAPI, mnemonic, btoa, Signal, @@ -622,6 +623,7 @@ }; // Update authorisation in database with the new grant signature await libloki.storage.savePairingAuthorisation(authorisation); + await lokiFileServerAPI.updateOurDeviceMapping(); await libloki.api.sendPairingAuthorisation( authorisation, secondaryDevicePubKey diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index b25223710..5b4db5575 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1048,78 +1048,8 @@ MessageReceiver.prototype.extend({ } return this.removeFromCache(envelope); }, - async validateAuthorisation(authorisation) { - const { - type, - primaryDevicePubKey, - secondaryDevicePubKey, - requestSignature, - grantSignature, - } = 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; - if (!primaryDevicePubKey || !secondaryDevicePubKey) { - window.log.warn( - 'Received a pairing request with missing pubkeys. Ignored.' - ); - return false; - } else if (!requestSignature) { - window.log.warn( - 'Received a pairing request with missing request signature. Ignored.' - ); - return false; - } else if (isRequest && alreadySecondaryDevice) { - window.log.warn( - 'Received a pairing request while being a secondary device. Ignored.' - ); - return false; - } else if (isRequest && authorisation.primaryDevicePubKey !== ourPubKey) { - window.log.warn( - 'Received a pairing request addressed to another pubkey. Ignored.' - ); - return false; - } else if (isRequest && authorisation.secondaryDevicePubKey === ourPubKey) { - window.log.warn('Received a pairing request from ourselves. Ignored.'); - return false; - } - try { - await libloki.crypto.verifyPairingAuthorisation( - primaryDevicePubKey, - secondaryDevicePubKey, - dcodeIO.ByteBuffer.wrap(requestSignature).toArrayBuffer(), - textsecure.protobuf.PairingAuthorisationMessage.Type.REQUEST - ); - } catch (e) { - window.log.warn( - 'Could not verify pairing request authorisation signature. Ignoring message.' - ); - window.log.error(e); - return false; - } - if (isGrant) { - try { - await libloki.crypto.verifyPairingAuthorisation( - primaryDevicePubKey, - secondaryDevicePubKey, - dcodeIO.ByteBuffer.wrap(grantSignature).toArrayBuffer(), - textsecure.protobuf.PairingAuthorisationMessage.Type.GRANT - ); - } catch (e) { - window.log.warn( - 'Could not verify pairing grant authorisation signature. Ignoring message.' - ); - window.log.error(e); - return false; - } - } - return true; - }, async handlePairingRequest(envelope, pairingRequest) { - const valid = await this.validateAuthorisation(pairingRequest); + const valid = await libloki.crypto.validateAuthorisation(pairingRequest); if (valid) { // Pairing dialog is open and is listening if (Whisper.events.isListenedTo('devicePairingRequestReceived')) { @@ -1138,7 +1068,7 @@ MessageReceiver.prototype.extend({ pairingAuthorisation, { dataMessage, syncMessage } ) { - const valid = await this.validateAuthorisation(pairingAuthorisation); + const valid = await libloki.crypto.validateAuthorisation(pairingAuthorisation); const alreadySecondaryDevice = !!window.storage.get('isSecondaryDevice'); let removedFromCache = false; if (alreadySecondaryDevice) { @@ -1214,25 +1144,8 @@ MessageReceiver.prototype.extend({ }) ); }, - async handleAuthorisationForContact(envelope, pairingAuthorisation) { - const valid = await this.validateAuthorisation(pairingAuthorisation); - if (!valid) { - window.log.warn( - 'Received invalid pairing authorisation for self. Could not verify signature. Ignoring.' - ); - } else { - const { - primaryDevicePubKey, - secondaryDevicePubKey, - } = pairingAuthorisation; - // ensure the primary device is a friend - const c = window.ConversationController.get(primaryDevicePubKey); - if (c && c.isFriend()) { - await libloki.storage.savePairingAuthorisation(pairingAuthorisation); - // send friend accept? - window.libloki.api.sendBackgroundMessage(secondaryDevicePubKey); - } - } + async handleAuthorisationForContact(envelope) { + window.log.error('Unexpected pairing request/authorisation received, ignoring.'); return this.removeFromCache(envelope); }, async handlePairingAuthorisationMessage(envelope, content) { @@ -1247,7 +1160,7 @@ MessageReceiver.prototype.extend({ content ); } - return this.handleAuthorisationForContact(envelope, pairingAuthorisation); + return this.handleAuthorisationForContact(envelope); }, async handleSecondaryDeviceFriendRequest(pubKey, deviceMapping) { diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 98b73f24f..e098689de 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -341,23 +341,6 @@ OutgoingMessage.prototype = { // Check if we need to attach the preKeys let sessionCipher; const isFriendRequest = this.messageType === 'friend-request'; - const isSecondaryDevice = !!window.storage.get('isSecondaryDevice'); - if (isFriendRequest && isSecondaryDevice) { - // Attach authorisation from primary device ONLY FOR FRIEND REQUEST - const ourPubKeyHex = textsecure.storage.user.getNumber(); - const pairingAuthorisation = await libloki.storage.getGrantAuthorisationForSecondaryPubKey( - ourPubKeyHex - ); - if (pairingAuthorisation) { - this.message.pairingAuthorisation = libloki.api.createPairingAuthorisationProtoMessage( - pairingAuthorisation - ); - } else { - window.log.error( - 'Could not find authorisation for our own pubkey while being secondary device.' - ); - } - } this.fallBackEncryption = this.fallBackEncryption || isFriendRequest; const flags = this.message.dataMessage ? this.message.dataMessage.get_flags()