From 2b58aff532f1ed3b2c9524a90baa13f831f3b864 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 9 Jun 2020 16:30:09 +1000 Subject: [PATCH] use pubkeys and toRawMessage() --- ts/session/protocols/SessionProtocol.ts | 51 ++++++----- .../session/protocols/SessionProtocol_test.ts | 86 ++++++++++--------- 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/ts/session/protocols/SessionProtocol.ts b/ts/session/protocols/SessionProtocol.ts index fbf531a09..8a4173538 100644 --- a/ts/session/protocols/SessionProtocol.ts +++ b/ts/session/protocols/SessionProtocol.ts @@ -3,10 +3,8 @@ import { SessionResetMessage } from '../messages/outgoing'; import { createOrUpdateItem, getItemById } from '../../../js/modules/data'; import { libloki, libsignal, textsecure } from '../../window'; import { MessageSender } from '../sending'; -import { RawMessage } from '../types/RawMessage'; -import { EncryptionType } from '../types/EncryptionType'; -import { TextEncoder } from 'util'; import * as MessageUtils from '../utils'; +import { PubKey } from '../types'; interface StringToNumberMap { [key: string]: number; @@ -51,9 +49,9 @@ export class SessionProtocol { } /** Returns true if we already have a session with that device */ - public static async hasSession(device: string): Promise { + public static async hasSession(pubkey: PubKey): Promise { // Session does not use the concept of a deviceId, thus it's always 1 - const address = new libsignal.SignalProtocolAddress(device, 1); + const address = new libsignal.SignalProtocolAddress(pubkey.key, 1); const sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, address @@ -66,11 +64,11 @@ export class SessionProtocol { * Returns true if we sent a session request to that device already OR * if a session request to that device is right now being sent. */ - public static async hasSentSessionRequest(device: string): Promise { + public static async hasSentSessionRequest(pubkey: PubKey): Promise { const pendingSend = SessionProtocol.pendingSendSessionsTimestamp.has( - device + pubkey.key ); - const hasSent = await SessionProtocol._hasSentSessionRequest(device); + const hasSent = await SessionProtocol._hasSentSessionRequest(pubkey.key); return pendingSend || hasSent; } @@ -82,17 +80,17 @@ export class SessionProtocol { * - we do not have a session request currently being send to that device */ public static async sendSessionRequestIfNeeded( - device: string + pubkey: PubKey ): Promise { if ( - (await SessionProtocol.hasSession(device)) || - (await SessionProtocol.hasSentSessionRequest(device)) + (await SessionProtocol.hasSession(pubkey)) || + (await SessionProtocol.hasSentSessionRequest(pubkey)) ) { return Promise.resolve(); } const preKeyBundle = await libloki.storage.getPreKeyBundleForContact( - device + pubkey.key ); const sessionReset = new SessionResetMessage({ @@ -101,51 +99,50 @@ export class SessionProtocol { }); try { - await SessionProtocol.sendSessionRequest(sessionReset, device); + await SessionProtocol.sendSessionRequest(sessionReset, pubkey); } catch (error) { - window.console.warn('Failed to send session request to:', device, error); + window.console.warn('Failed to send session request to:', pubkey.key, error); } } /** */ public static async sendSessionRequest( message: SessionResetMessage, - device: string + pubkey: PubKey ): Promise { const timestamp = Date.now(); // mark the session as being pending send with current timestamp // so we know we already triggered a new session with that device - SessionProtocol.pendingSendSessionsTimestamp.add(device); + SessionProtocol.pendingSendSessionsTimestamp.add(pubkey.key); try { - // TODO: Send out the request via MessageSender - const rawMessage = MessageUtils.toRawMessage(device, message); + const rawMessage = MessageUtils.toRawMessage(pubkey, message); await MessageSender.send(rawMessage); - await SessionProtocol.updateSentSessionTimestamp(device, timestamp); + await SessionProtocol.updateSentSessionTimestamp(pubkey.key, timestamp); } catch (e) { throw e; } finally { - SessionProtocol.pendingSendSessionsTimestamp.delete(device); + SessionProtocol.pendingSendSessionsTimestamp.delete(pubkey.key); } } /** * Called when a session is establish so we store on database this info. */ - public static async onSessionEstablished(device: string) { + public static async onSessionEstablished(pubkey: PubKey) { // remove our existing sent timestamp for that device - return SessionProtocol.updateSentSessionTimestamp(device, undefined); + return SessionProtocol.updateSentSessionTimestamp(pubkey.key, undefined); } public static async shouldProcessSessionRequest( - device: string, + pubkey: PubKey, messageTimestamp: number ): Promise { const existingSentTimestamp = - (await SessionProtocol.getSentSessionRequest(device)) || 0; + (await SessionProtocol.getSentSessionRequest(pubkey.key)) || 0; const existingProcessedTimestamp = - (await SessionProtocol.getProcessedSessionRequest(device)) || 0; + (await SessionProtocol.getProcessedSessionRequest(pubkey.key)) || 0; return ( messageTimestamp > existingSentTimestamp && @@ -153,8 +150,8 @@ export class SessionProtocol { ); } - public static async onSessionRequestProcessed(device: string) { - return SessionProtocol.updateProcessedSessionTimestamp(device, Date.now()); + public static async onSessionRequestProcessed(pubkey: PubKey) { + return SessionProtocol.updateProcessedSessionTimestamp(pubkey.key, Date.now()); } public static reset() { diff --git a/ts/test/session/protocols/SessionProtocol_test.ts b/ts/test/session/protocols/SessionProtocol_test.ts index 3e5889ded..71940c9bd 100644 --- a/ts/test/session/protocols/SessionProtocol_test.ts +++ b/ts/test/session/protocols/SessionProtocol_test.ts @@ -6,11 +6,13 @@ import { UserUtil } from '../../../util'; import { SessionResetMessage } from '../../../session/messages/outgoing'; import { TextEncoder } from 'util'; import { MessageSender } from '../../../session/sending'; +import { PubKey } from '../../../session/types'; // tslint:disable-next-line: max-func-body-length describe('SessionProtocol', () => { const sandbox = sinon.createSandbox(); const ourNumber = 'ourNumber'; + const pubkey = new PubKey('deviceid'); let getItemById: sinon.SinonStub; let send: sinon.SinonStub; @@ -61,17 +63,17 @@ describe('SessionProtocol', () => { describe('db fetch', () => { it('protocol: should fetch from DB `sentSessionsTimestamp` and `processedSessionsTimestamp`', async () => { - await SessionProtocol.hasSentSessionRequest('test'); + await SessionProtocol.hasSentSessionRequest(pubkey); expect(getItemById.calledWith('sentSessionsTimestamp')); expect(getItemById.calledWith('processedSessionsTimestamp')); expect(getItemById.callCount).to.equal(2); }); it('protocol: should fetch only once', async () => { - await SessionProtocol.hasSentSessionRequest('test'); - await SessionProtocol.hasSentSessionRequest('test'); - await SessionProtocol.hasSentSessionRequest('test'); - await SessionProtocol.hasSentSessionRequest('test'); + await SessionProtocol.hasSentSessionRequest(pubkey); + await SessionProtocol.hasSentSessionRequest(pubkey); + await SessionProtocol.hasSentSessionRequest(pubkey); + await SessionProtocol.hasSentSessionRequest(pubkey); expect(getItemById.calledWith('sentSessionsTimestamp')); expect(getItemById.calledWith('processedSessionsTimestamp')); expect(getItemById.callCount).to.equal(2); @@ -81,33 +83,33 @@ describe('SessionProtocol', () => { describe('sendSessionRequest', () => { beforeEach(async () => { // trigger a sessionReset - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceID'); + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); }); it('protocol: sendSessionRequest should add the deviceID to the sentMap', async () => { expect(SessionProtocol.getSentSessionsTimestamp()) - .to.have.property('deviceID') + .to.have.property('deviceid') .to.be.approximately(Date.now(), 100); }); it('protocol: sendSessionRequest should not have pendingSend set after', async () => { expect( SessionProtocol.getPendingSendSessionTimestamp() - ).to.not.have.property('deviceID'); + ).to.not.have.property('deviceid'); }); }); describe('onSessionEstablished', () => { beforeEach(async () => { // add an existing entry in the sentMap - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); }); it('protocol: onSessionEstablished should remove the device in sentTimestamps', async () => { expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( 'deviceid' ); - await SessionProtocol.onSessionEstablished('deviceid'); + await SessionProtocol.onSessionEstablished(pubkey); expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property( 'deviceid' ); @@ -115,7 +117,7 @@ describe('SessionProtocol', () => { it('protocol: onSessionEstablished should remove the device in sentTimestamps and ONLY that one', async () => { // add a second item to the map - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid2'); + await SessionProtocol.sendSessionRequest(resetMessage, new PubKey('deviceid2')); expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( 'deviceid' @@ -124,7 +126,7 @@ describe('SessionProtocol', () => { 'deviceid2' ); - await SessionProtocol.onSessionEstablished('deviceid'); + await SessionProtocol.onSessionEstablished(pubkey); expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property( 'deviceid' ); @@ -136,7 +138,7 @@ describe('SessionProtocol', () => { describe('hasSentSessionRequest', () => { it('protocol: hasSentSessionRequest returns false if a message was not sent to that device', async () => { - const hasSent = await SessionProtocol.hasSentSessionRequest('deviceid'); + const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); expect(hasSent).to.be.equal( false, 'hasSent should be false for `deviceid`' @@ -145,8 +147,8 @@ describe('SessionProtocol', () => { it('protocol: hasSentSessionRequest returns true if a message is already sent for that device', async () => { // add an existing entry in the sentMap - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); - const hasSent = await SessionProtocol.hasSentSessionRequest('deviceid'); + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); + const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); expect(hasSent).to.be.equal( true, 'hasSent should be true for `deviceid`' @@ -159,14 +161,14 @@ describe('SessionProtocol', () => { describe('sendSessionRequestIfNeeded', () => { it('protocol: sendSessionRequestIfNeeded should send a new sessionMessage ', async () => { // not called before, so the message reset sending should be triggered - await SessionProtocol.sendSessionRequestIfNeeded('deviceid'); + await SessionProtocol.sendSessionRequestIfNeeded(pubkey); expect(send.callCount).to.be.equal( 1, 'MessageSender.send() should have been called' ); // check that the map is updated with that ID - const hasSent = await SessionProtocol.hasSentSessionRequest('deviceid'); + const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); expect(hasSent).to.be.equal( true, 'hasSent should be true for `deviceid`' @@ -174,14 +176,14 @@ describe('SessionProtocol', () => { }); it('protocol: sendSessionRequestIfNeeded should NOT send a new sessionMessage on second try ', async () => { - await SessionProtocol.sendSessionRequestIfNeeded('deviceid'); + await SessionProtocol.sendSessionRequestIfNeeded(pubkey); expect(send.callCount).to.be.equal( 1, 'MessageSender.send() should have been called' ); // check that the map is updated with that ID - const hasSent = await SessionProtocol.hasSentSessionRequest('deviceid'); + const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); expect(hasSent).to.be.equal( true, 'hasSent should be true for `deviceid`' @@ -189,7 +191,7 @@ describe('SessionProtocol', () => { send.resetHistory(); // trigger a second call, Message.send().calledCount should still be 1 - await SessionProtocol.sendSessionRequestIfNeeded('deviceid'); + await SessionProtocol.sendSessionRequestIfNeeded(pubkey); expect(send.callCount).to.be.equal( 0, 'MessageSender.send() should NOT have been called a second time' @@ -200,7 +202,7 @@ describe('SessionProtocol', () => { describe('onSessionRequestProcessed', () => { it('protocol: onSessionRequestProcessed should insert a new item in the processedMap ', async () => { // trigger the requestProcessed and check the map is updated - await SessionProtocol.onSessionRequestProcessed('deviceid'); + await SessionProtocol.onSessionRequestProcessed(pubkey); expect(SessionProtocol.getProcessedSessionsTimestamp()) .to.have.property('deviceid') .to.be.approximately(Date.now(), 5); @@ -210,14 +212,14 @@ describe('SessionProtocol', () => { // trigger the requestProcessed and check the map is updated // then trigger it a second time, and expect a change in the processed timestamp - await SessionProtocol.onSessionRequestProcessed('deviceid'); + await SessionProtocol.onSessionRequestProcessed(pubkey); expect(SessionProtocol.getProcessedSessionsTimestamp()) .to.have.property('deviceid') .to.be.approximately(Date.now(), 5); await timeout(5); const oldTimestamp = SessionProtocol.getProcessedSessionsTimestamp() .deviceid; - await SessionProtocol.onSessionRequestProcessed('deviceid'); + await SessionProtocol.onSessionRequestProcessed(pubkey); expect(SessionProtocol.getProcessedSessionsTimestamp()) .to.have.property('deviceid') .to.be.approximately(Date.now(), 5) @@ -227,10 +229,10 @@ describe('SessionProtocol', () => { describe('shouldProcessSessionRequest', () => { it('protocol: shouldProcessSessionRequest returns true if timestamp is more recent than processed timestamp', async () => { - await SessionProtocol.onSessionRequestProcessed('deviceid'); // adds a Date.now() entry + await SessionProtocol.onSessionRequestProcessed(pubkey); // adds a Date.now() entry expect( SessionProtocol.shouldProcessSessionRequest( - 'deviceid', + pubkey, Date.now() + 1000 ) ).to.be.eventually.equal( @@ -241,7 +243,7 @@ describe('SessionProtocol', () => { it('protocol: shouldProcessSessionRequest returns true if there is no processed timestamp yet for this device', async () => { expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', 100) + SessionProtocol.shouldProcessSessionRequest(pubkey, 100) ).to.be.eventually.equal( true, 'shouldProcessSessionRequest should return false when existingProcessed is empty for this device' @@ -249,9 +251,9 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns false if timestamp is less recent than current processed timestamp', async () => { - await SessionProtocol.onSessionRequestProcessed('deviceid'); // adds a Date.now() entry + await SessionProtocol.onSessionRequestProcessed(pubkey); // adds a Date.now() entry expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', 100) + SessionProtocol.shouldProcessSessionRequest(pubkey, 100) ).to.be.eventually.equal( false, 'shouldProcessSessionRequest should return false when existingProcessed is more recent' @@ -259,9 +261,9 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns false if timestamp is less recent than current sent timestamp', async () => { - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); // adds a Date.now() entry + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); // adds a Date.now() entry expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', 100) + SessionProtocol.shouldProcessSessionRequest(pubkey, 100) ).to.be.eventually.equal( false, 'shouldProcessSessionRequest should return false when existingSent is more recent' @@ -269,10 +271,10 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns true if timestamp is more recent than current sent timestamp', async () => { - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); // adds a Date.now() entry + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); // adds a Date.now() entry expect( SessionProtocol.shouldProcessSessionRequest( - 'deviceid', + pubkey, Date.now() + 1000 ) ).to.be.eventually.equal( @@ -283,7 +285,7 @@ describe('SessionProtocol', () => { it('protocol: shouldProcessSessionRequest returns true if there is no sent timestamp', async () => { expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', 100) + SessionProtocol.shouldProcessSessionRequest(pubkey, 100) ).to.be.eventually.equal( true, 'shouldProcessSessionRequest should return true as there is no sent timestamp' @@ -291,12 +293,12 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns false if there is a more recent sent but a less recent processed', async () => { - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); // adds a Date.now() entry + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); // adds a Date.now() entry await timeout(100); - await SessionProtocol.onSessionRequestProcessed('deviceid'); // adds a Date.now() entry 100ms after + await SessionProtocol.onSessionRequestProcessed(pubkey); // adds a Date.now() entry 100ms after expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', Date.now() - 50) + SessionProtocol.shouldProcessSessionRequest(pubkey, Date.now() - 50) ).to.be.eventually.equal( false, 'shouldProcessSessionRequest should return false if there is a more recent sent but a less recent processed' @@ -304,12 +306,12 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns false if there is a more recent processed but a less recent sent', async () => { - await SessionProtocol.onSessionRequestProcessed('deviceid'); // adds a Date.now() entry + await SessionProtocol.onSessionRequestProcessed(pubkey); // adds a Date.now() entry await timeout(100); - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); // adds a Date.now() entry 100ms after + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); // adds a Date.now() entry 100ms after expect( - SessionProtocol.shouldProcessSessionRequest('deviceid', Date.now() - 50) + SessionProtocol.shouldProcessSessionRequest(pubkey, Date.now() - 50) ).to.be.eventually.equal( false, 'shouldProcessSessionRequest should return false if there is a more recent processed but a less recent sent' @@ -317,11 +319,11 @@ describe('SessionProtocol', () => { }); it('protocol: shouldProcessSessionRequest returns true if both sent and processed timestamp are older', async () => { - await SessionProtocol.onSessionRequestProcessed('deviceid'); // adds a Date.now() entry - await SessionProtocol.sendSessionRequest(resetMessage, 'deviceid'); // adds a Date.now() entry + await SessionProtocol.onSessionRequestProcessed(pubkey); // adds a Date.now() entry + await SessionProtocol.sendSessionRequest(resetMessage, pubkey); // adds a Date.now() entry expect( SessionProtocol.shouldProcessSessionRequest( - 'deviceid', + pubkey, Date.now() + 1000 ) ).to.be.eventually.equal(