diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 9abce0997..b83a55b5e 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -202,15 +202,19 @@ OutgoingMessage.prototype = { return messagePartCount * 160; }, + convertMessageToText(message) { + const messageBuffer = message.toArrayBuffer(); + const plaintext = new Uint8Array( + this.getPaddedMessageLength(messageBuffer.byteLength + 1) - 1 + ); + plaintext.set(new Uint8Array(messageBuffer)); + plaintext[messageBuffer.byteLength] = 0x80; + return plaintext; + }, getPlaintext() { if (!this.plaintext) { - const messageBuffer = this.message.toArrayBuffer(); - this.plaintext = new Uint8Array( - this.getPaddedMessageLength(messageBuffer.byteLength + 1) - 1 - ); - this.plaintext.set(new Uint8Array(messageBuffer)); - this.plaintext[messageBuffer.byteLength] = 0x80; + this.plaintext = this.convertMessageToText(this.message); } return this.plaintext; }, @@ -275,6 +279,18 @@ OutgoingMessage.prototype = { const address = new libsignal.SignalProtocolAddress(number, deviceId); const ourKey = textsecure.storage.user.getNumber(); const options = {}; + const fallBackEncryption = new libloki.FallBackSessionCipher(address); + + // Check if we need to attach the preKeys + let preKeys = {}; + if (this.attachPrekeys) { + // Encrypt them with the fallback + const preKeyBundleMessage = await libloki.getPreKeyBundleForNumber(number); + const textBundle = this.convertMessageToText(preKeyBundleMessage); + const encryptedBundle = await fallBackEncryption.encrypt(textBundle); + preKeys = { preKeyBundleMessage: encryptedBundle.body }; + window.log.info('attaching prekeys to outgoing message'); + } // No limit on message keys if we're communicating with our other devices if (ourKey === number) { @@ -283,7 +299,7 @@ OutgoingMessage.prototype = { let sessionCipher; if (this.fallBackEncryption) { - sessionCipher = new libloki.FallBackSessionCipher(address); + sessionCipher = fallBackEncryption; } else { sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, @@ -292,26 +308,26 @@ OutgoingMessage.prototype = { ); } ciphers[address.getDeviceId()] = sessionCipher; - return sessionCipher - .encrypt(plaintext) - .then(ciphertext => { - if (!this.fallBackEncryption) - // eslint-disable-next-line no-param-reassign - ciphertext.body = new Uint8Array( - dcodeIO.ByteBuffer.wrap( - ciphertext.body, - 'binary' - ).toArrayBuffer() - ); - return ciphertext; - }) - .then(ciphertext => ({ - type: ciphertext.type, - ourKey, - sourceDevice: 1, - destinationRegistrationId: ciphertext.registrationId, - content: ciphertext.body, - })); + + // Encrypt our plain text + const ciphertext = await sessionCipher.encrypt(plaintext); + if (!this.fallBackEncryption) { + // eslint-disable-next-line no-param-reassign + ciphertext.body = new Uint8Array( + dcodeIO.ByteBuffer.wrap( + ciphertext.body, + 'binary' + ).toArrayBuffer() + ); + } + return { + type: ciphertext.type, // FallBackSessionCipher sets this to FRIEND_REQUEST + ourKey, + sourceDevice: 1, + destinationRegistrationId: ciphertext.registrationId, + content: ciphertext.body, + ...preKeys, + }; }) ) .then(async outgoingObjects => { @@ -441,14 +457,14 @@ OutgoingMessage.prototype = { return this.getStaleDeviceIdsForNumber(number).then(updateDevices => this.getKeysForNumber(number, updateDevices) .then(async keysFound => { - let attachPrekeys = false; + this.attachPrekeys = false; if (!keysFound) { log.info('Fallback encryption enabled'); this.fallBackEncryption = true; - attachPrekeys = true; + this.attachPrekeys = true; } else if (conversation) { try { - attachPrekeys = !conversation.isKeyExchangeCompleted(); + this.attachPrekeys = !conversation.isKeyExchangeCompleted(); } catch (e) { // do nothing } @@ -457,13 +473,6 @@ OutgoingMessage.prototype = { if (this.fallBackEncryption && conversation) { conversation.onFriendRequestSent(); } - - if (attachPrekeys) { - log.info('attaching prekeys to outgoing message'); - this.message.preKeyBundleMessage = await libloki.getPreKeyBundleForNumber( - number - ); - } }) .then(this.reloadDevicesAndSend(number, true)) .catch(error => { diff --git a/protos/SignalService.proto b/protos/SignalService.proto index e76ff9218..5e2b905de 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -24,6 +24,7 @@ message Envelope { optional bytes content = 8; // Contains an encrypted Content optional string serverGuid = 9; optional uint64 serverTimestamp = 10; + optional PreKeyBundleMessage preKeyBundleMessage = 101; } @@ -33,7 +34,6 @@ message Content { optional CallMessage callMessage = 3; optional NullMessage nullMessage = 4; optional ReceiptMessage receiptMessage = 5; - optional PreKeyBundleMessage preKeyBundleMessage = 6; } message PreKeyBundleMessage {