diff --git a/integration_test/message_sync_test.js b/integration_test/message_sync_test.js index 4f40a89d3..3aa078e23 100644 --- a/integration_test/message_sync_test.js +++ b/integration_test/message_sync_test.js @@ -50,7 +50,7 @@ describe('Message Syncing', function() { // Linking Alice2 to Alice1 // alice2 should trigger auto FR with bob1 as it's one of her friend - // and alice2 should trigger a SESSION_REQUEST with bob1 as he is in a closed group with her + // and alice2 should trigger a FALLBACK_MESSAGE with bob1 as he is in a closed group with her await common.linkApp2ToApp(Alice1, Alice2, common.TEST_PUBKEY1); await common.timeout(25000); @@ -119,7 +119,7 @@ describe('Message Syncing', function() { // once autoFR is auto-accepted, alice2 trigger contact sync await common.logsContains( bob1Logs, - `Received SESSION_REQUEST from source: ${alice2Pubkey}`, + `Received FALLBACK_MESSAGE from source: ${alice2Pubkey}`, 1 ); await common.logsContains( diff --git a/libloki/api.js b/libloki/api.js index d187cfb45..596807898 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -8,7 +8,7 @@ const DebugFlagsEnum = { GROUP_SYNC_MESSAGES: 1, CONTACT_SYNC_MESSAGES: 2, - SESSION_REQUEST_MESSAGES: 8, + FALLBACK_MESSAGES: 8, SESSION_MESSAGE_SENDING: 16, SESSION_BACKGROUND_MESSAGE: 32, GROUP_REQUEST_INFO: 64, diff --git a/libloki/crypto.js b/libloki/crypto.js index cec6ae99a..806aed9b9 100644 --- a/libloki/crypto.js +++ b/libloki/crypto.js @@ -153,7 +153,7 @@ ivAndCiphertext ).toString('binary'); return { - type: textsecure.protobuf.Envelope.Type.SESSION_REQUEST, + type: textsecure.protobuf.Envelope.Type.FALLBACK_MESSAGE, body: binaryIvAndCiphertext, registrationId: undefined, }; diff --git a/libloki/test/crypto_test.js b/libloki/test/crypto_test.js index 8a294c4ba..4d57df09a 100644 --- a/libloki/test/crypto_test.js +++ b/libloki/test/crypto_test.js @@ -19,12 +19,12 @@ describe('Crypto', () => { fallbackCipher = new libloki.crypto.FallBackSessionCipher(address); }); - it('should encrypt fallback cipher messages as friend requests', async () => { + it('should encrypt fallback cipher messages as fallback messages', async () => { const buffer = new ArrayBuffer(10); const { type } = await fallbackCipher.encrypt(buffer); assert.strictEqual( type, - textsecure.protobuf.Envelope.Type.SESSION_REQUEST + textsecure.protobuf.Envelope.Type.FALLBACK_MESSAGE ); }); diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 3ef1c3799..0dd3ed43a 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -325,8 +325,7 @@ OutgoingMessage.prototype = { // END_SESSION means Session reset message const isEndSession = flags === textsecure.protobuf.DataMessage.Flags.END_SESSION; - const isSessionRequest = - flags === textsecure.protobuf.DataMessage.Flags.SESSION_REQUEST; + const isSessionRequest = false; if (enableFallBackEncryption || isEndSession) { // Encrypt them with the fallback diff --git a/protos/SignalService.proto b/protos/SignalService.proto index 0a5300c5d..bd0f937c0 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -13,7 +13,7 @@ message Envelope { RECEIPT = 5; UNIDENTIFIED_SENDER = 6; MEDIUM_GROUP_CIPHERTEXT = 7; - SESSION_REQUEST = 101; // contains prekeys and is using simple encryption + FALLBACK_MESSAGE = 101; // contains prekeys and is using simple encryption } optional Type type = 1; diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index 3e8d105b9..0022131f2 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -183,9 +183,9 @@ async function decryptUnidentifiedSender( } // We might have substituted the type based on decrypted content - if (type === SignalService.Envelope.Type.SESSION_REQUEST) { + if (type === SignalService.Envelope.Type.FALLBACK_MESSAGE) { // eslint-disable-next-line no-param-reassign - envelope.type = SignalService.Envelope.Type.SESSION_REQUEST; + envelope.type = SignalService.Envelope.Type.FALLBACK_MESSAGE; } const blocked = await isBlocked(sender.getName()); @@ -227,8 +227,8 @@ async function doDecrypt( return lokiSessionCipher.decryptWhisperMessage(ciphertext).then(unpad); case SignalService.Envelope.Type.MEDIUM_GROUP_CIPHERTEXT: return decryptForMediumGroup(envelope, ciphertext); - case SignalService.Envelope.Type.SESSION_REQUEST: { - window.log.info('session-request message from ', envelope.source); + case SignalService.Envelope.Type.FALLBACK_MESSAGE: { + window.log.info('fallback message from ', envelope.source); const fallBackSessionCipher = new libloki.crypto.FallBackSessionCipher( address @@ -344,13 +344,13 @@ export async function innerHandleContentMessage( const content = SignalService.Content.decode(new Uint8Array(plaintext)); - const { SESSION_REQUEST } = SignalService.Envelope.Type; + const { FALLBACK_MESSAGE } = SignalService.Envelope.Type; await ConversationController.getOrCreateAndWait(envelope.source, 'private'); - if (envelope.type === SESSION_REQUEST) { - await handleSessionRequestMessage(envelope, content); - } else { + if (content.preKeyBundleMessage) { + await handleSessionRequestMessage(envelope, content.preKeyBundleMessage); + } else if (envelope.type !== FALLBACK_MESSAGE) { const device = new PubKey(envelope.source); await SessionProtocol.onSessionEstablished(device); diff --git a/ts/receiver/sessionHandling.ts b/ts/receiver/sessionHandling.ts index 6a8966149..1dd04c571 100644 --- a/ts/receiver/sessionHandling.ts +++ b/ts/receiver/sessionHandling.ts @@ -25,10 +25,9 @@ export async function handleEndSession(number: string): Promise { export async function handleSessionRequestMessage( envelope: EnvelopePlus, - content: SignalService.Content + preKeyBundleMessage: SignalService.IPreKeyBundleMessage ) { const { libsignal, libloki, StringView, textsecure, dcodeIO, log } = window; - const { preKeyBundleMessage } = content; window.console.log( `Received SESSION_REQUEST from source: ${envelope.source}` diff --git a/ts/session/crypto/MessageEncrypter.ts b/ts/session/crypto/MessageEncrypter.ts index 9a9471e1a..ded12577b 100644 --- a/ts/session/crypto/MessageEncrypter.ts +++ b/ts/session/crypto/MessageEncrypter.ts @@ -53,7 +53,7 @@ export async function encrypt( } let innerCipherText: CipherTextObject; - if (encryptionType === EncryptionType.SessionRequest) { + if (encryptionType === EncryptionType.Fallback) { const cipher = new window.libloki.crypto.FallBackSessionCipher(address); innerCipherText = await cipher.encrypt(plainText.buffer); } else { diff --git a/ts/session/protocols/SessionProtocol.ts b/ts/session/protocols/SessionProtocol.ts index 45b3673f6..8e58f465c 100644 --- a/ts/session/protocols/SessionProtocol.ts +++ b/ts/session/protocols/SessionProtocol.ts @@ -144,7 +144,7 @@ export class SessionProtocol { SessionProtocol.pendingSendSessionsTimestamp.add(pubkey.key); try { - const rawMessage = MessageUtils.toRawMessage(pubkey, message); + const rawMessage = await MessageUtils.toRawMessage(pubkey, message); await MessageSender.send(rawMessage); await SessionProtocol.updateSentSessionTimestamp(pubkey.key, timestamp); } catch (e) { diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index f8c089d14..9c99d892e 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -130,10 +130,9 @@ export class MessageQueue implements MessageQueueInterface { const isMediumGroup = GroupUtils.isMediumGroup(device); const hasSession = await SessionProtocol.hasSession(device); + // If we don't have a session then try and establish one and then continue sending messages if (!isMediumGroup && !hasSession) { await SessionProtocol.sendSessionRequestIfNeeded(device); - - return; } const jobQueue = this.getJobQueue(device); diff --git a/ts/session/sending/PendingMessageCache.ts b/ts/session/sending/PendingMessageCache.ts index a26cea8c6..7ccf7fafb 100644 --- a/ts/session/sending/PendingMessageCache.ts +++ b/ts/session/sending/PendingMessageCache.ts @@ -41,7 +41,7 @@ export class PendingMessageCache { message: ContentMessage ): Promise { await this.loadFromDBIfNeeded(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); // Does it exist in cache already? if (this.find(rawMessage)) { diff --git a/ts/session/types/EncryptionType.ts b/ts/session/types/EncryptionType.ts index 86d1aeda7..d48f962aa 100644 --- a/ts/session/types/EncryptionType.ts +++ b/ts/session/types/EncryptionType.ts @@ -1,5 +1,5 @@ export enum EncryptionType { Signal, - SessionRequest, + Fallback, MediumGroup, } diff --git a/ts/session/utils/Messages.ts b/ts/session/utils/Messages.ts index d09cb45b9..269275373 100644 --- a/ts/session/utils/Messages.ts +++ b/ts/session/utils/Messages.ts @@ -1,18 +1,30 @@ import { RawMessage } from '../types/RawMessage'; -import { ContentMessage, SessionRequestMessage } from '../messages/outgoing'; +import { + ContentMessage, + MediumGroupMessage, + SessionRequestMessage, +} from '../messages/outgoing'; import { EncryptionType, PubKey } from '../types'; +import { SessionProtocol } from '../protocols'; -export function toRawMessage( +export async function toRawMessage( device: PubKey, message: ContentMessage -): RawMessage { +): Promise { const timestamp = message.timestamp; const ttl = message.ttl(); const plainTextBuffer = message.plainTextBuffer(); - const encryption = - message instanceof SessionRequestMessage - ? EncryptionType.SessionRequest - : EncryptionType.Signal; + + let encryption: EncryptionType; + if (message instanceof MediumGroupMessage) { + encryption = EncryptionType.MediumGroup; + } else if (message instanceof SessionRequestMessage) { + encryption = EncryptionType.Fallback; + } else { + // If we don't have a session yet then send using fallback encryption until we have a session + const hasSession = await SessionProtocol.hasSession(device); + encryption = hasSession ? EncryptionType.Signal : EncryptionType.Fallback; + } // tslint:disable-next-line: no-unnecessary-local-variable const rawMessage: RawMessage = { diff --git a/ts/test/session/crypto/MessageEncrypter_test.ts b/ts/test/session/crypto/MessageEncrypter_test.ts index 7612f3c37..d46b80fae 100644 --- a/ts/test/session/crypto/MessageEncrypter_test.ts +++ b/ts/test/session/crypto/MessageEncrypter_test.ts @@ -66,11 +66,7 @@ describe('MessageEncrypter', () => { Stubs.FallBackSessionCipherStub.prototype, 'encrypt' ); - await MessageEncrypter.encrypt( - '1', - data, - EncryptionType.SessionRequest - ); + await MessageEncrypter.encrypt('1', data, EncryptionType.Fallback); expect(spy.called).to.equal( true, 'FallbackSessionCipher.encrypt should be called.' @@ -83,11 +79,7 @@ describe('MessageEncrypter', () => { Stubs.FallBackSessionCipherStub.prototype, 'encrypt' ); - await MessageEncrypter.encrypt( - '1', - data, - EncryptionType.SessionRequest - ); + await MessageEncrypter.encrypt('1', data, EncryptionType.Fallback); const paddedData = MessageEncrypter.padPlainTextBuffer(data); const firstArgument = new Uint8Array(spy.args[0][0]); @@ -99,7 +91,7 @@ describe('MessageEncrypter', () => { const result = await MessageEncrypter.encrypt( '1', data, - EncryptionType.SessionRequest + EncryptionType.Fallback ); expect(result.envelopeType).to.deep.equal( SignalService.Envelope.Type.UNIDENTIFIED_SENDER @@ -144,7 +136,7 @@ describe('MessageEncrypter', () => { describe('Sealed Sender', () => { it('should pass the correct values to SecretSessionCipher encrypt', async () => { - const types = [EncryptionType.SessionRequest, EncryptionType.Signal]; + const types = [EncryptionType.Fallback, EncryptionType.Signal]; for (const type of types) { const spy = sandbox.spy( Stubs.SecretSessionCipherStub.prototype, diff --git a/ts/test/session/messages/RawMessage_test.ts b/ts/test/session/messages/RawMessage_test.ts deleted file mode 100644 index 208247b68..000000000 --- a/ts/test/session/messages/RawMessage_test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { expect } from 'chai'; -import { beforeEach } from 'mocha'; - -import { - DeviceUnlinkMessage, - SessionRequestMessage, -} from '../../../session/messages/outgoing'; -import { SignalService } from '../../../protobuf'; -import { toRawMessage } from '../../../session/utils/Messages'; -import { EncryptionType, PubKey, RawMessage } from '../../../session/types'; -import { TestUtils } from '../../test-utils'; -import { TextEncoder } from 'util'; - -describe('toRawMessage', () => { - let message: DeviceUnlinkMessage; - const pubkey: PubKey = TestUtils.generateFakePubKey(); - let raw: RawMessage; - - beforeEach(() => { - const timestamp = Date.now(); - message = new DeviceUnlinkMessage({ timestamp }); - raw = toRawMessage(pubkey, message); - }); - - it('copied fields are set', () => { - expect(raw).to.have.property('ttl', message.ttl()); - expect(raw) - .to.have.property('plainTextBuffer') - .to.be.deep.equal(message.plainTextBuffer()); - expect(raw).to.have.property('timestamp', message.timestamp); - expect(raw).to.have.property('identifier', message.identifier); - expect(raw).to.have.property('device', pubkey.key); - }); - - it('encryption is set to SESSION_REQUEST if message is of instance SessionRequestMessage', () => { - const preKeyBundle = { - deviceId: 123456, - preKeyId: 654321, - signedKeyId: 111111, - preKey: new TextEncoder().encode('preKey'), - signature: new TextEncoder().encode('signature'), - signedKey: new TextEncoder().encode('signedKey'), - identityKey: new TextEncoder().encode('identityKey'), - }; - const sessionRequest = new SessionRequestMessage({ - timestamp: Date.now(), - preKeyBundle, - }); - const sessionRequestRaw = toRawMessage(pubkey, sessionRequest); - expect(sessionRequestRaw).to.have.property( - 'encryption', - EncryptionType.SessionRequest - ); - }); - - it('encryption is set to Signal if message is not of instance SessionRequestMessage', () => { - expect(raw).to.have.property('encryption', EncryptionType.Signal); - }); -}); diff --git a/ts/test/session/sending/MessageQueue_test.ts b/ts/test/session/sending/MessageQueue_test.ts index 7c7241f9f..4e1644d27 100644 --- a/ts/test/session/sending/MessageQueue_test.ts +++ b/ts/test/session/sending/MessageQueue_test.ts @@ -83,7 +83,7 @@ describe('MessageQueue', () => { }); describe('processPending', () => { - it('will send session request message if no session', async () => { + it('will send session request if no session and not sending to medium group', async () => { hasSessionStub.resolves(false); isMediumGroupStub.returns(false); @@ -97,48 +97,33 @@ describe('MessageQueue', () => { await expect(stubCallPromise).to.be.fulfilled; }); - it('will send message if session exists', async () => { - hasSessionStub.resolves(true); - isMediumGroupStub.returns(false); - sendStub.resolves(); + it('will not send session request if sending to medium group', async () => { + hasSessionStub.resolves(false); + isMediumGroupStub.returns(true); const device = TestUtils.generateFakePubKey(); - await pendingMessageCache.add(device, TestUtils.generateChatMessage()); - - const successPromise = PromiseUtils.waitForTask(done => { - messageQueueStub.events.once('success', done); - }); - await messageQueueStub.processPending(device); - await expect(successPromise).to.be.fulfilled; - expect(sendSessionRequestIfNeededStub.called).to.equal( - false, - 'Session request triggered when we have a session.' - ); + + expect(sendSessionRequestIfNeededStub.callCount).to.equal(0); }); - it('will send message if sending to medium group', async () => { - isMediumGroupStub.returns(true); - sendStub.resolves(); + it('will send messages', async () => { + for (const hasSession of [true, false]) { + hasSessionStub.resolves(hasSession); - const device = TestUtils.generateFakePubKey(); - await pendingMessageCache.add(device, TestUtils.generateChatMessage()); - - const successPromise = PromiseUtils.waitForTask(done => { - messageQueueStub.events.once('success', done); - }); + const device = TestUtils.generateFakePubKey(); + await pendingMessageCache.add(device, TestUtils.generateChatMessage()); - await messageQueueStub.processPending(device); - await expect(successPromise).to.be.fulfilled; - expect(sendSessionRequestIfNeededStub.called).to.equal( - false, - 'Session request triggered on medium group' - ); + const successPromise = PromiseUtils.waitForTask(done => { + messageQueueStub.events.once('success', done); + }); + await messageQueueStub.processPending(device); + await expect(successPromise).to.be.fulfilled; + } }); it('should remove message from cache', async () => { hasSessionStub.resolves(true); - isMediumGroupStub.returns(false); const events = ['success', 'fail']; for (const event of events) { @@ -166,8 +151,6 @@ describe('MessageQueue', () => { describe('events', () => { it('should send a success event if message was sent', async () => { hasSessionStub.resolves(true); - isMediumGroupStub.returns(false); - sendStub.resolves(); const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); @@ -188,7 +171,6 @@ describe('MessageQueue', () => { it('should send a fail event if something went wrong while sending', async () => { hasSessionStub.resolves(true); - isMediumGroupStub.returns(false); sendStub.throws(new Error('failure')); const spy = sandbox.spy(); diff --git a/ts/test/session/sending/PendingMessageCache_test.ts b/ts/test/session/sending/PendingMessageCache_test.ts index 5f806b5dc..995d424e3 100644 --- a/ts/test/session/sending/PendingMessageCache_test.ts +++ b/ts/test/session/sending/PendingMessageCache_test.ts @@ -1,8 +1,10 @@ import { expect } from 'chai'; +import * as sinon from 'sinon'; import * as _ from 'lodash'; import { MessageUtils } from '../../../session/utils'; import { TestUtils } from '../../../test/test-utils'; import { PendingMessageCache } from '../../../session/sending/PendingMessageCache'; +import { SessionProtocol } from '../../../session/protocols'; // Equivalent to Data.StorageItem interface StorageItem { @@ -11,6 +13,7 @@ interface StorageItem { } describe('PendingMessageCache', () => { + const sandbox = sinon.createSandbox(); // Initialize new stubbed cache let data: StorageItem; let pendingMessageCacheStub: PendingMessageCache; @@ -36,9 +39,12 @@ describe('PendingMessageCache', () => { }); pendingMessageCacheStub = new PendingMessageCache(); + + sandbox.stub(SessionProtocol, 'hasSession').resolves(true); }); afterEach(() => { + sandbox.restore(); TestUtils.restoreStubs(); }); @@ -53,7 +59,7 @@ describe('PendingMessageCache', () => { it('can add to cache', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); @@ -86,7 +92,7 @@ describe('PendingMessageCache', () => { it('can remove from cache', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); @@ -105,7 +111,7 @@ describe('PendingMessageCache', () => { it('should only remove messages with different timestamp and device', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); await TestUtils.timeout(5); @@ -195,7 +201,7 @@ describe('PendingMessageCache', () => { it('can find nothing when empty', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); const foundMessage = pendingMessageCacheStub.find(rawMessage); expect(foundMessage, 'a message was found in empty cache').to.be.undefined; @@ -204,7 +210,7 @@ describe('PendingMessageCache', () => { it('can find message in cache', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); diff --git a/ts/test/session/utils/Messages_test.ts b/ts/test/session/utils/Messages_test.ts index a3775abfb..cd8b052b9 100644 --- a/ts/test/session/utils/Messages_test.ts +++ b/ts/test/session/utils/Messages_test.ts @@ -1,7 +1,14 @@ import chai from 'chai'; +import * as sinon from 'sinon'; +import crypto from 'crypto'; import { TestUtils } from '../../test-utils/'; import { MessageUtils } from '../../../session/utils/'; -import { PubKey } from '../../../session/types/'; +import { EncryptionType, PubKey } from '../../../session/types/'; +import { SessionProtocol } from '../../../session/protocols'; +import { + MediumGroupChatMessage, + SessionRequestMessage, +} from '../../../session/messages/outgoing'; // tslint:disable-next-line: no-require-imports no-var-requires const chaiAsPromised = require('chai-as-promised'); @@ -10,12 +17,26 @@ chai.use(chaiAsPromised); const { expect } = chai; describe('Message Utils', () => { + const sandbox = sinon.createSandbox(); + + afterEach(() => { + sandbox.restore(); + }); + describe('toRawMessage', () => { + let hasSessionStub: sinon.SinonStub<[PubKey], Promise>; + + beforeEach(() => { + hasSessionStub = sandbox + .stub(SessionProtocol, 'hasSession') + .resolves(true); + }); + it('can convert to raw message', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); expect(Object.keys(rawMessage)).to.have.length(6); expect(rawMessage.identifier).to.exist; @@ -24,13 +45,21 @@ describe('Message Utils', () => { expect(rawMessage.plainTextBuffer).to.exist; expect(rawMessage.timestamp).to.exist; expect(rawMessage.ttl).to.exist; + + expect(rawMessage.identifier).to.equal(message.identifier); + expect(rawMessage.device).to.equal(device.key); + expect(rawMessage.plainTextBuffer).to.deep.equal( + message.plainTextBuffer() + ); + expect(rawMessage.timestamp).to.equal(message.timestamp); + expect(rawMessage.ttl).to.equal(message.ttl()); }); it('should generate valid plainTextBuffer', async () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); const rawBuffer = rawMessage.plainTextBuffer; const rawBufferJSON = JSON.stringify(rawBuffer); @@ -50,7 +79,7 @@ describe('Message Utils', () => { const device = TestUtils.generateFakePubKey(); const message = TestUtils.generateChatMessage(); - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = await MessageUtils.toRawMessage(device, message); const derivedPubKey = PubKey.from(rawMessage.device); expect(derivedPubKey).to.exist; @@ -59,5 +88,63 @@ describe('Message Utils', () => { 'pubkey of message was not converted correctly' ); }); + + it('should set encryption to MediumGroup if a MediumGroupMessage is passed in', async () => { + hasSessionStub.resolves(true); + + const device = TestUtils.generateFakePubKey(); + const groupId = TestUtils.generateFakePubKey(); + const chatMessage = TestUtils.generateChatMessage(); + const message = new MediumGroupChatMessage({ chatMessage, groupId }); + + const rawMessage = await MessageUtils.toRawMessage(device, message); + expect(rawMessage.encryption).to.equal(EncryptionType.MediumGroup); + }); + + it('should set encryption to Fallback if a SessionRequestMessage is passed in', async () => { + hasSessionStub.resolves(true); + + const device = TestUtils.generateFakePubKey(); + const preKeyBundle = { + deviceId: 123456, + preKeyId: 654321, + signedKeyId: 111111, + preKey: crypto.randomBytes(16), + signature: crypto.randomBytes(16), + signedKey: crypto.randomBytes(16), + identityKey: crypto.randomBytes(16), + }; + const sessionRequest = new SessionRequestMessage({ + timestamp: Date.now(), + preKeyBundle, + }); + + const rawMessage = await MessageUtils.toRawMessage( + device, + sessionRequest + ); + + expect(rawMessage.encryption).to.equal(EncryptionType.Fallback); + }); + + it('should set encryption to Fallback on other messages if we do not have a session', async () => { + hasSessionStub.resolves(false); + + const device = TestUtils.generateFakePubKey(); + const message = TestUtils.generateChatMessage(); + const rawMessage = await MessageUtils.toRawMessage(device, message); + + expect(rawMessage.encryption).to.equal(EncryptionType.Fallback); + }); + + it('should set encryption to Signal on other messages if we have a session', async () => { + hasSessionStub.resolves(true); + + const device = TestUtils.generateFakePubKey(); + const message = TestUtils.generateChatMessage(); + const rawMessage = await MessageUtils.toRawMessage(device, message); + + expect(rawMessage.encryption).to.equal(EncryptionType.Signal); + }); }); }); diff --git a/ts/test/test-utils/stubs/ciphers/FallBackSessionCipherStub.ts b/ts/test/test-utils/stubs/ciphers/FallBackSessionCipherStub.ts index d53b258d6..acff841fe 100644 --- a/ts/test/test-utils/stubs/ciphers/FallBackSessionCipherStub.ts +++ b/ts/test/test-utils/stubs/ciphers/FallBackSessionCipherStub.ts @@ -5,7 +5,7 @@ import { StringUtils } from '../../../../session/utils'; export class FallBackSessionCipherStub { public async encrypt(buffer: ArrayBuffer): Promise { return { - type: SignalService.Envelope.Type.SESSION_REQUEST, + type: SignalService.Envelope.Type.FALLBACK_MESSAGE, body: StringUtils.decode(buffer, 'binary'), }; }