| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -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,140 @@ 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) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const valid = await this.validateAuthorisation(pairingRequest);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!valid) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    await window.libloki.storage.savePairingAuthorisation(pairingRequest);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Whisper.events.trigger(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'devicePairingRequestReceived',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      pairingRequest.secondaryDevicePubKey
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  async handleAuthorisationForSelf(pairingAuthorisation) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const valid = await this.validateAuthorisation(pairingAuthorisation);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!valid) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      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) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const valid = await this.validateAuthorisation(pairingAuthorisation);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!valid) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      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) {
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |