| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -36174,10 +36174,11 @@ SessionCipher.prototype = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          return Internal.SessionRecord.deserialize(serialized);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  encrypt: function(plaintext) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  encrypt: function(buffer, encoding) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (!(plaintext instanceof ArrayBuffer)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          throw new Error("Expected plaintext to be an ArrayBuffer");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (!(buffer instanceof ArrayBuffer)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          throw new Error("Expected buffer to be an ArrayBuffer");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      var address = this.remoteAddress.toString();
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -36185,10 +36186,10 @@ SessionCipher.prototype = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      var msg = new Internal.protobuf.WhisperMessage();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      var paddedPlaintext = new Uint8Array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          this.getPaddedMessageLength(plaintext.byteLength + 1) - 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          this.getPaddedMessageLength(buffer.byteLength + 1) - 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      paddedPlaintext.set(new Uint8Array(plaintext));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      paddedPlaintext[plaintext.byteLength] = 0x80;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      paddedPlaintext.set(new Uint8Array(buffer));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      paddedPlaintext[buffer.byteLength] = 0x80;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return Promise.all([
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          this.storage.getIdentityKeyPair(),
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -36274,18 +36275,19 @@ SessionCipher.prototype = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return messagePartCount * 160;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  decryptWhisperMessage: function(messageBytes) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  decryptWhisperMessage: function(buffer, encoding) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var address = this.remoteAddress.toString();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return this.getRecord(address).then(function(record) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (!record) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                throw new Error("No record for device " + address);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            var messageProto = buffer.slice(1, buffer.byteLength - 8);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            var message = Internal.protobuf.WhisperMessage.decode(messageProto);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            var remoteEphemeralKey = message.ephemeralKey.toArrayBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            var session = record.getSessionByRemoteEphemeralKey(remoteEphemeralKey);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return this.doDecryptWhisperMessage(util.toArrayBuffer(messageBytes), session).then(function(plaintext) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                record.updateSessionState(session);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                return this.storage.storeSession(address, record.serialize()).then(function() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    return plaintext;
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -36294,11 +36296,16 @@ SessionCipher.prototype = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }.bind(this));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }.bind(this));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  decryptPreKeyWhisperMessage: function(encodedMessage, encoding) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  decryptPreKeyWhisperMessage: function(buffer, encoding) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      var version = buffer.readUint8();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if ((version & 0xF) > 3 || (version >> 4) < 3) {  // min version > 3 or max version < 3
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          throw new Error("Incompatible version number on PreKeyWhisperMessage");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          var address = this.remoteAddress.toString();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          return this.getRecord(address).then(function(record) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(encodedMessage, encoding);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(buffer);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              if (!record) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  if (preKeyProto.registrationId === undefined) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                      throw new Error("No registrationId");
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -36332,8 +36339,8 @@ SessionCipher.prototype = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        throw new Error("Expected messageBytes to be an ArrayBuffer");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    var version = (new Uint8Array(messageBytes))[0];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (version !== ((3 << 4) | 3)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        throw new Error("Bad version number on WhisperMessage");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if ((version & 0xF) > 3 || (version >> 4) < 3) {  // min version > 3 or max version < 3
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        throw new Error("Incompatible version number on WhisperMessage");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    var mac = messageBytes.slice(messageBytes.byteLength - 8, messageBytes.byteLength);
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -38082,7 +38089,7 @@ MessageReceiver.prototype.extend({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        switch(envelope.type) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            case textsecure.protobuf.Envelope.Type.CIPHERTEXT:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                promise = sessionCipher.decryptWhisperMessage(ciphertext.toArrayBuffer());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                promise = sessionCipher.decryptWhisperMessage(ciphertext);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                console.log('prekey whisper message');
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -38100,16 +38107,8 @@ MessageReceiver.prototype.extend({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }.bind(this));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    decryptPreKeyWhisperMessage: function(ciphertext, sessionCipher, address) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ciphertext.mark();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var version = ciphertext.readUint8();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if ((version & 0xF) > 3 || (version >> 4) < 3) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // min version > 3 or max version < 3
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            throw new Error("Incompatible version byte");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return sessionCipher.decryptPreKeyWhisperMessage(ciphertext).catch(function(e) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (e.message === 'Unknown identity key') {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ciphertext.reset(); // restore the version byte.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // create an error that the UI will pick up and ask the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // user if they want to re-negotiate
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                throw new textsecure.IncomingIdentityKeyError(
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -38292,8 +38291,7 @@ MessageReceiver.prototype.extend({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        then(decryptAttachment).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        then(updateAttachment);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    tryMessageAgain: function(from, encodedMessage) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var ciphertext = dcodeIO.ByteBuffer.wrap(encodedMessage);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    tryMessageAgain: function(from, ciphertext) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var address = libsignal.SignalProtocolAddress.fromString(from);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        console.log('retrying prekey whisper message');
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |