From 6ab05e28dfdb34f9ff75dcb71b80f61a78a685e2 Mon Sep 17 00:00:00 2001 From: sachaaaaa Date: Fri, 23 Aug 2019 16:09:18 +1000 Subject: [PATCH 1/3] Handle incoming pairing authorisation message --- libtextsecure/message_receiver.js | 133 +++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 21 deletions(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index ee575edc0..632f73a15 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -16,6 +16,7 @@ /* global localServerPort: false */ /* global lokiMessageAPI: false */ /* global lokiP2pAPI: false */ +/* global Whisper: false */ /* eslint-disable more/no-then */ /* eslint-disable no-unreachable */ @@ -1022,47 +1023,137 @@ MessageReceiver.prototype.extend({ } return this.removeFromCache(envelope); }, - async handlePairingAuthorisationMessage(envelope, pairingAuthorisation) { + async validateAuthorisation(authorisation) { const { type, primaryDevicePubKey, secondaryDevicePubKey, - signature, - } = pairingAuthorisation; - const sigArrayBuffer = dcodeIO.ByteBuffer.wrap(signature).toArrayBuffer(); - if ( - type === - textsecure.protobuf.PairingAuthorisationMessage.Type.PAIRING_REQUEST - ) { - window.log.info( - `Received pairing authorisation from ${primaryDevicePubKey}` + 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 (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(), + type + ); + } catch (e) { + window.log.warn( + 'Could not verify pairing request authorisation signature. Ignoring message.' ); - let validAuthorisation = false; + window.log.error(e); + return false; + } + if (isGrant) { try { await libloki.crypto.verifyPairingAuthorisation( primaryDevicePubKey, secondaryDevicePubKey, - sigArrayBuffer, + dcodeIO.ByteBuffer.wrap(grantSignature).toArrayBuffer(), type ); - validAuthorisation = true; } catch (e) { + window.log.warn( + 'Could not verify pairing grant authorisation signature. Ignoring message.' + ); window.log.error(e); + return false; } - if (validAuthorisation) { - await libloki.storage.savePairingAuthorisation( - primaryDevicePubKey, - secondaryDevicePubKey, - sigArrayBuffer - ); - } else { + } + return true; + }, + async handlePairingRequest(pairingRequest) { + if (!this.validateAuthorisation(pairingRequest)) { + return; + } + window.libloki.storage.savePairingAuthorisation(pairingRequest); + Whisper.events.trigger( + 'devicePairingRequestReceived', + pairingRequest.secondaryDevicePubKey + ); + }, + async handleAuthorisationForSelf(pairingAuthorisation) { + if (!this.validateAuthorisation(pairingAuthorisation)) { + return; + } + const { type, primaryDevicePubKey } = pairingAuthorisation; + if (type === textsecure.protobuf.PairingAuthorisationMessage.Type.GRANT) { + // Authorisation received to become a secondary device + window.log.info( + `Received pairing authorisation from ${primaryDevicePubKey}` + ); + const alreadySecondaryDevice = window.storage.get('isSecondaryDevice'); + if (alreadySecondaryDevice) { window.log.warn( - 'Could not verify pairing authorisation signature. Ignoring message.' + 'Received an unexpected pairing authorisation (device is already paired as secondary device). Ignoring.' ); + return; } + await libloki.storage.savePairingAuthorisation(pairingAuthorisation); + // Set current device as secondary. + // This will ensure the authorisation is sent + // along with each friend request. + window.storage.remove('secondaryDeviceStatus'); + window.storage.put('isSecondaryDevice', true); + Whisper.events.trigger('secondaryDeviceRegistration'); } else { window.log.warn('Unimplemented pairing authorisation message type'); } + }, + async handleAuthorisationForContact(pairingAuthorisation) { + if (!this.validateAuthorisation(pairingAuthorisation)) { + return; + } + const { primaryDevicePubKey, secondaryDevicePubKey } = pairingAuthorisation; + // ensure the primary device is a friend + const c = window.ConversationController.get(primaryDevicePubKey); + if (!c || !c.isFriend()) { + return; + } + await libloki.storage.savePairingAuthorisation(pairingAuthorisation); + // send friend accept? + window.libloki.api.sendBackgroundMessage(secondaryDevicePubKey); + }, + async handlePairingAuthorisationMessage(envelope, pairingAuthorisation) { + const { type, secondaryDevicePubKey } = pairingAuthorisation; + if (type === textsecure.protobuf.PairingAuthorisationMessage.Type.REQUEST) { + await this.handlePairingRequest(pairingAuthorisation); + } else if (secondaryDevicePubKey === textsecure.storage.user.getNumber()) { + await this.handleAuthorisationForSelf(pairingAuthorisation); + } else { + await this.handleAuthorisationForContact(pairingAuthorisation); + } return this.removeFromCache(envelope); }, handleDataMessage(envelope, msg) { From c7dc79e7f9705c2d2a1a766fe701707cf9119c9a Mon Sep 17 00:00:00 2001 From: sachaaaaa Date: Mon, 26 Aug 2019 15:00:41 +1000 Subject: [PATCH 2/3] Fix missing awaits! --- libtextsecure/message_receiver.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 632f73a15..100958825 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1094,17 +1094,19 @@ MessageReceiver.prototype.extend({ return true; }, async handlePairingRequest(pairingRequest) { - if (!this.validateAuthorisation(pairingRequest)) { + const valid = await this.validateAuthorisation(pairingRequest); + if (!valid) { return; } - window.libloki.storage.savePairingAuthorisation(pairingRequest); + await window.libloki.storage.savePairingAuthorisation(pairingRequest); Whisper.events.trigger( 'devicePairingRequestReceived', pairingRequest.secondaryDevicePubKey ); }, async handleAuthorisationForSelf(pairingAuthorisation) { - if (!this.validateAuthorisation(pairingAuthorisation)) { + const valid = await this.validateAuthorisation(pairingAuthorisation); + if (!valid) { return; } const { type, primaryDevicePubKey } = pairingAuthorisation; @@ -1132,7 +1134,8 @@ MessageReceiver.prototype.extend({ } }, async handleAuthorisationForContact(pairingAuthorisation) { - if (!this.validateAuthorisation(pairingAuthorisation)) { + const valid = this.validateAuthorisation(pairingAuthorisation); + if (!valid) { return; } const { primaryDevicePubKey, secondaryDevicePubKey } = pairingAuthorisation; From 8ef54890b2c9d722fb008256fae8c572f5df92a4 Mon Sep 17 00:00:00 2001 From: sachaaaaa <40749766+sachaaaaa@users.noreply.github.com> Date: Mon, 26 Aug 2019 15:17:51 +1000 Subject: [PATCH 3/3] Update libtextsecure/message_receiver.js Co-Authored-By: Mikunj Varsani --- libtextsecure/message_receiver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 100958825..9dce8934a 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1134,7 +1134,7 @@ MessageReceiver.prototype.extend({ } }, async handleAuthorisationForContact(pairingAuthorisation) { - const valid = this.validateAuthorisation(pairingAuthorisation); + const valid = await this.validateAuthorisation(pairingAuthorisation); if (!valid) { return; }