From b8ec9bd99526cba3f2a08850558394591092f392 Mon Sep 17 00:00:00 2001 From: Vincent Date: Thu, 4 Jun 2020 15:38:21 +1000 Subject: [PATCH] Typify PubKey --- .../outgoing/content/sync/SyncMessage.ts | 6 +- ts/session/sending/MessageQueue.ts | 2 +- ts/session/sending/MessageQueueInterface.ts | 5 - ts/session/sending/PendingMessageCache.ts | 18 +++- ts/session/types/PubKey.ts | 47 ++++++++++ ts/session/types/index.ts | 3 + ts/session/utils/MessageUtils.ts | 89 ------------------ ts/session/utils/Messages.ts | 55 +++++++++++ ts/session/utils/index.ts | 2 +- .../sending/PendingMessageCache_test.ts | 94 +++++++++---------- 10 files changed, 169 insertions(+), 152 deletions(-) create mode 100644 ts/session/types/PubKey.ts create mode 100644 ts/session/types/index.ts delete mode 100644 ts/session/utils/MessageUtils.ts create mode 100644 ts/session/utils/Messages.ts diff --git a/ts/session/messages/outgoing/content/sync/SyncMessage.ts b/ts/session/messages/outgoing/content/sync/SyncMessage.ts index 3eb336dc6..30ba3d0fb 100644 --- a/ts/session/messages/outgoing/content/sync/SyncMessage.ts +++ b/ts/session/messages/outgoing/content/sync/SyncMessage.ts @@ -1,7 +1,7 @@ import { ContentMessage } from '../ContentMessage'; import { SignalService } from '../../../../../protobuf'; -export abstract class SyncMessage extends ContentMessage { +export class SyncMessage extends ContentMessage { public ttl(): number { return this.getDefaultTTL(); } @@ -12,5 +12,7 @@ export abstract class SyncMessage extends ContentMessage { }); } - protected abstract syncProto(): SignalService.SyncMessage; + protected syncProto(): SignalService.SyncMessage { + return new SignalService.SyncMessage({}); + } } diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index 909eb6b7d..7d975f9a1 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -58,7 +58,7 @@ export class MessageQueue implements MessageQueueInterface { // If you see an open group message just call // MessageSender.sendToOpenGroup directly. } - + public sendSyncMessage(message: ContentMessage) { // PSEDUOCODE // if message is undefined diff --git a/ts/session/sending/MessageQueueInterface.ts b/ts/session/sending/MessageQueueInterface.ts index 182eb1e46..0a74f0164 100644 --- a/ts/session/sending/MessageQueueInterface.ts +++ b/ts/session/sending/MessageQueueInterface.ts @@ -1,12 +1,7 @@ import { -<<<<<<< HEAD OpenGroupMessage, ContentMessage, SyncMessage, -======= - ContentMessage as OutgoingContentMessage, - OpenGroupMessage, ->>>>>>> 935ac8d8f911616731c20aa5b45b79bea6895731 } from '../messages/outgoing'; import { RawMessage } from '../types/RawMessage'; import { TypedEventEmitter } from '../utils'; diff --git a/ts/session/sending/PendingMessageCache.ts b/ts/session/sending/PendingMessageCache.ts index 0658d731e..2ae437f6f 100644 --- a/ts/session/sending/PendingMessageCache.ts +++ b/ts/session/sending/PendingMessageCache.ts @@ -1,7 +1,8 @@ import * as Data from '../../../js/modules/data'; import { RawMessage } from '../types/RawMessage'; import { ChatMessage, ContentMessage } from '../messages/outgoing'; -import { MessageUtils, PubKey } from '../utils'; +import * as MessageUtils from '../utils'; +import { PubKey } from '../types'; // TODO: We should be able to import functions straight from the db here without going through the window object @@ -80,9 +81,16 @@ export class PendingMessageCache { public getDevices(): Array { // Gets all devices with pending messages - const pubkeys = [...new Set(this.cache.map(m => m.device))]; + const pubkeyStrings = [...new Set(this.cache.map(m => m.device))]; - return pubkeys.map(d => PubKey.from(d)); + const pubkeys: Array = []; + pubkeyStrings.forEach(pubkey => { + if (PubKey.validate(pubkey)) { + pubkeys.push(new PubKey(pubkey)); + } + }); + + return pubkeys; } public async init() { @@ -90,7 +98,7 @@ export class PendingMessageCache { this.cache = messages; } - public async getFromStorage(): Promise> { + private async getFromStorage(): Promise> { // tslint:disable-next-line: no-backbone-get-set-outside-model const pendingMessagesData = await Data.getItemById('pendingMessages'); const pendingMessagesJSON = pendingMessagesData @@ -109,7 +117,7 @@ export class PendingMessageCache { return encodedPendingMessages; } - public async syncCacheWithDB() { + private async syncCacheWithDB() { // Only call when adding / removing from cache. const encodedPendingMessages = JSON.stringify(this.cache) || ''; await Data.createOrUpdateItem({ diff --git a/ts/session/types/PubKey.ts b/ts/session/types/PubKey.ts new file mode 100644 index 000000000..9ab308cfb --- /dev/null +++ b/ts/session/types/PubKey.ts @@ -0,0 +1,47 @@ + +import * as crypto from 'crypto'; + +export enum PubKeyCategory { + Primary = 'priamry', + Secondary = 'secondary', + Group = 'group', +} + +export class PubKey { + private static readonly PUBKEY_LEN = 66; + private static readonly regex: string = `^05[0-9a-fA-F]{${PubKey.PUBKEY_LEN - 2}}$`; + public readonly key: string; + public type?: PubKeyCategory; + + constructor(pubkeyString: string, type?: PubKeyCategory) { + PubKey.validate(pubkeyString); + this.key = pubkeyString; + this.type = type; + } + + public static from(pubkeyString: string): PubKey | undefined { + // Returns a new instance if the pubkey is valid + if (PubKey.validate(pubkeyString)) { + return new PubKey(pubkeyString); + } + + return undefined; + } + + public static validate(pubkeyString: string): boolean { + if (pubkeyString.match(PubKey.regex)) { + return true; + } + + return false; + } + + public static generateFake(): PubKey { + // Generates a mock pubkey for testing + const numBytes = (PubKey.PUBKEY_LEN / 2) - 1; + const hexBuffer = crypto.randomBytes(numBytes).toString('hex'); + const pubkeyString = `05${hexBuffer}`; + + return new PubKey(pubkeyString); + } +} diff --git a/ts/session/types/index.ts b/ts/session/types/index.ts new file mode 100644 index 000000000..c7c994c52 --- /dev/null +++ b/ts/session/types/index.ts @@ -0,0 +1,3 @@ +export * from './EncryptionType'; +export * from './RawMessage'; +export * from './PubKey'; diff --git a/ts/session/utils/MessageUtils.ts b/ts/session/utils/MessageUtils.ts deleted file mode 100644 index 44fe09746..000000000 --- a/ts/session/utils/MessageUtils.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { RawMessage } from '../types/RawMessage'; -import { ContentMessage } from '../messages/outgoing'; -import { EncryptionType } from '../types/EncryptionType'; -import * as crypto from 'crypto'; - -function toRawMessage(device: PubKey, message: ContentMessage): RawMessage { - const ttl = message.ttl(); - const timestamp = message.timestamp; - const plainTextBuffer = message.plainTextBuffer(); - - // Get EncryptionType depending on message type. - // let encryption: EncryptionType; - - // switch (message.constructor.name) { - // case MessageType.Chat: - // encryption = EncryptionType.Signal; - // break; - // case MessageType.SessionReset: - // encryption = EncryptionType - // } - - // export enum EncryptionType { - // Signal, - // SessionReset, - // MediumGroup, - // } - - // tslint:disable-next-line: no-unnecessary-local-variable - const rawMessage: RawMessage = { - identifier: message.identifier, - plainTextBuffer, - timestamp, - device: device.key, - ttl, - encryption: EncryptionType.Signal, - }; - - return rawMessage; -} - -export enum PubKeyType { - Primary = 'priamry', - Secondary = 'secondary', - Group = 'group', -} - -export class PubKey { - private static readonly regex: string = '^0[0-9a-fA-F]{65}$'; - public readonly key: string; - public type?: PubKeyType; - - constructor(pubkeyString: string, type?: PubKeyType) { - PubKey.validate(pubkeyString); - this.key = pubkeyString; - this.type = type; - } - - public static from(pubkeyString: string): PubKey { - // Returns a new instance if the pubkey is valid - if (PubKey.validate(pubkeyString)) { - return new PubKey(pubkeyString); - } - - throw new Error('Invalid pubkey format'); - } - - public static validate(pubkeyString: string): boolean { - if (pubkeyString.match(PubKey.regex)) { - return true; - } - - throw new Error('Invalid pubkey format'); - } - - public static generate(): PubKey { - // Generates a mock pubkey for testing - const PUBKEY_LEN = 66; - const numBytes = PUBKEY_LEN / 2; - const hexBuffer = crypto.randomBytes(numBytes).toString('hex'); - const pubkeyString = `0${hexBuffer}`.slice(0, PUBKEY_LEN); - - return new PubKey(pubkeyString); - } -} - -// Functions / Tools -export const MessageUtils = { - toRawMessage, -}; diff --git a/ts/session/utils/Messages.ts b/ts/session/utils/Messages.ts new file mode 100644 index 000000000..5fe68ad47 --- /dev/null +++ b/ts/session/utils/Messages.ts @@ -0,0 +1,55 @@ +import * as crypto from 'crypto'; +import uuid from 'uuid'; + +import { RawMessage } from '../types/RawMessage'; +import { ChatMessage, ContentMessage } from '../messages/outgoing'; +import { EncryptionType } from '../types/EncryptionType'; + + +export function toRawMessage(device: PubKey, message: ContentMessage): RawMessage { + const ttl = message.ttl(); + const timestamp = message.timestamp; + const plainTextBuffer = message.plainTextBuffer(); + + // Get EncryptionType depending on message type. + // let encryption: EncryptionType; + + // switch (message.constructor.name) { + // case MessageType.Chat: + // encryption = EncryptionType.Signal; + // break; + // case MessageType.SessionReset: + // encryption = EncryptionType + // } + + // export enum EncryptionType { + // Signal, + // SessionReset, + // MediumGroup, + // } + + // tslint:disable-next-line: no-unnecessary-local-variable + const rawMessage: RawMessage = { + identifier: message.identifier, + plainTextBuffer, + timestamp, + device: device.key, + ttl, + encryption: EncryptionType.Signal, + }; + + return rawMessage; +} + +export function generateUniqueChatMessage(): ChatMessage { + return new ChatMessage({ + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', + identifier: uuid(), + timestamp: Date.now(), + attachments: undefined, + quote: undefined, + expireTimer: undefined, + lokiProfile: undefined, + preview: undefined, + }); +} diff --git a/ts/session/utils/index.ts b/ts/session/utils/index.ts index aa6aef99e..96904245d 100644 --- a/ts/session/utils/index.ts +++ b/ts/session/utils/index.ts @@ -1,3 +1,3 @@ export * from './TypedEmitter'; export * from './JobQueue'; -export * from './MessageUtils'; +export * from './Messages'; diff --git a/ts/test/session/sending/PendingMessageCache_test.ts b/ts/test/session/sending/PendingMessageCache_test.ts index 299b1db88..80f7e28d5 100644 --- a/ts/test/session/sending/PendingMessageCache_test.ts +++ b/ts/test/session/sending/PendingMessageCache_test.ts @@ -3,9 +3,13 @@ import * as sinon from 'sinon'; import uuid from 'uuid'; import { ChatMessage } from '../../../session/messages/outgoing'; -import { MessageUtils, PubKey } from '../../../session/utils'; +import * as MessageUtils from '../../../session/utils'; + +import { TestUtils } from '../../../test/test-utils'; import { PendingMessageCache } from '../../../session/sending/PendingMessageCache'; import { RawMessage } from '../../../session/types/RawMessage'; +import { PubKey } from '../../../session/types'; +import * as Data from '../../../../js/modules/data'; describe('PendingMessageCache', () => { const sandbox = sinon.createSandbox(); @@ -13,34 +17,26 @@ describe('PendingMessageCache', () => { // tslint:disable-next-line: promise-function-async const wrapInPromise = (value: any) => - new Promise(r => { - r(value); - }); - - const generateUniqueMessage = (): ChatMessage => { - return new ChatMessage({ - body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', - identifier: uuid(), - timestamp: Date.now(), - attachments: undefined, - quote: undefined, - expireTimer: undefined, - lokiProfile: undefined, - preview: undefined, + new Promise(resolve => { + resolve(value); }); - }; beforeEach(async () => { - const mockStorageObject = wrapInPromise([] as Array); - const voidPromise = wrapInPromise(undefined); - // Stub out methods which touch the database. - sandbox - .stub(PendingMessageCache.prototype, 'getFromStorage') - .returns(mockStorageObject); - sandbox - .stub(PendingMessageCache.prototype, 'syncCacheWithDB') - .returns(voidPromise); + // Stub out methods which touch the database + const storageID = 'pendingMessages'; + let data: Data.StorageItem = { + id: storageID, + value: '', + }; + + TestUtils.stubData('getItemById').withArgs('pendingMessages').callsFake(async () => { + return wrapInPromise(data); + }); + + TestUtils.stubData('createOrUpdateItem').callsFake((item: Data.StorageItem) => { + data = item; + }); // Initialize new stubbed cache pendingMessageCacheStub = new PendingMessageCache(); @@ -60,8 +56,8 @@ describe('PendingMessageCache', () => { }); it('can add to cache', async () => { - const device = PubKey.generate(); - const message = generateUniqueMessage(); + const device = PubKey.generateFake(); + const message = MessageUtils.generateUniqueChatMessage(); const rawMessage = MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); @@ -77,8 +73,8 @@ describe('PendingMessageCache', () => { }); it('can remove from cache', async () => { - const device = PubKey.generate(); - const message = generateUniqueMessage(); + const device = PubKey.generateFake(); + const message = MessageUtils.generateUniqueChatMessage(); const rawMessage = MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); @@ -98,16 +94,16 @@ describe('PendingMessageCache', () => { it('can get devices', async () => { const cacheItems = [ { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, ]; @@ -130,12 +126,12 @@ describe('PendingMessageCache', () => { it('can get pending for device', async () => { const cacheItems = [ { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, ]; @@ -157,8 +153,8 @@ describe('PendingMessageCache', () => { }); it('can find nothing when empty', async () => { - const device = PubKey.generate(); - const message = generateUniqueMessage(); + const device = PubKey.generateFake(); + const message = MessageUtils.generateUniqueChatMessage(); const rawMessage = MessageUtils.toRawMessage(device, message); const foundMessage = pendingMessageCacheStub.find(rawMessage); @@ -166,8 +162,8 @@ describe('PendingMessageCache', () => { }); it('can find message in cache', async () => { - const device = PubKey.generate(); - const message = generateUniqueMessage(); + const device = PubKey.generateFake(); + const message = MessageUtils.generateUniqueChatMessage(); const rawMessage = MessageUtils.toRawMessage(device, message); await pendingMessageCacheStub.add(device, message); @@ -183,16 +179,16 @@ describe('PendingMessageCache', () => { it('can clear cache', async () => { const cacheItems = [ { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, { - device: PubKey.generate(), - message: generateUniqueMessage(), + device: PubKey.generateFake(), + message: MessageUtils.generateUniqueChatMessage(), }, ];