Typify PubKey

pull/1157/head
Vincent 5 years ago
parent 372754e360
commit b8ec9bd995

@ -1,7 +1,7 @@
import { ContentMessage } from '../ContentMessage'; import { ContentMessage } from '../ContentMessage';
import { SignalService } from '../../../../../protobuf'; import { SignalService } from '../../../../../protobuf';
export abstract class SyncMessage extends ContentMessage { export class SyncMessage extends ContentMessage {
public ttl(): number { public ttl(): number {
return this.getDefaultTTL(); 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({});
}
} }

@ -58,7 +58,7 @@ export class MessageQueue implements MessageQueueInterface {
// If you see an open group message just call // If you see an open group message just call
// MessageSender.sendToOpenGroup directly. // MessageSender.sendToOpenGroup directly.
} }
public sendSyncMessage(message: ContentMessage) { public sendSyncMessage(message: ContentMessage) {
// PSEDUOCODE // PSEDUOCODE
// if message is undefined // if message is undefined

@ -1,12 +1,7 @@
import { import {
<<<<<<< HEAD
OpenGroupMessage, OpenGroupMessage,
ContentMessage, ContentMessage,
SyncMessage, SyncMessage,
=======
ContentMessage as OutgoingContentMessage,
OpenGroupMessage,
>>>>>>> 935ac8d8f911616731c20aa5b45b79bea6895731
} from '../messages/outgoing'; } from '../messages/outgoing';
import { RawMessage } from '../types/RawMessage'; import { RawMessage } from '../types/RawMessage';
import { TypedEventEmitter } from '../utils'; import { TypedEventEmitter } from '../utils';

@ -1,7 +1,8 @@
import * as Data from '../../../js/modules/data'; import * as Data from '../../../js/modules/data';
import { RawMessage } from '../types/RawMessage'; import { RawMessage } from '../types/RawMessage';
import { ChatMessage, ContentMessage } from '../messages/outgoing'; 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 // 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<PubKey> { public getDevices(): Array<PubKey> {
// Gets all devices with pending messages // 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<PubKey> = [];
pubkeyStrings.forEach(pubkey => {
if (PubKey.validate(pubkey)) {
pubkeys.push(new PubKey(pubkey));
}
});
return pubkeys;
} }
public async init() { public async init() {
@ -90,7 +98,7 @@ export class PendingMessageCache {
this.cache = messages; this.cache = messages;
} }
public async getFromStorage(): Promise<Array<RawMessage>> { private async getFromStorage(): Promise<Array<RawMessage>> {
// tslint:disable-next-line: no-backbone-get-set-outside-model // tslint:disable-next-line: no-backbone-get-set-outside-model
const pendingMessagesData = await Data.getItemById('pendingMessages'); const pendingMessagesData = await Data.getItemById('pendingMessages');
const pendingMessagesJSON = pendingMessagesData const pendingMessagesJSON = pendingMessagesData
@ -109,7 +117,7 @@ export class PendingMessageCache {
return encodedPendingMessages; return encodedPendingMessages;
} }
public async syncCacheWithDB() { private async syncCacheWithDB() {
// Only call when adding / removing from cache. // Only call when adding / removing from cache.
const encodedPendingMessages = JSON.stringify(this.cache) || ''; const encodedPendingMessages = JSON.stringify(this.cache) || '';
await Data.createOrUpdateItem({ await Data.createOrUpdateItem({

@ -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);
}
}

@ -0,0 +1,3 @@
export * from './EncryptionType';
export * from './RawMessage';
export * from './PubKey';

@ -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,
};

@ -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,
});
}

@ -1,3 +1,3 @@
export * from './TypedEmitter'; export * from './TypedEmitter';
export * from './JobQueue'; export * from './JobQueue';
export * from './MessageUtils'; export * from './Messages';

@ -3,9 +3,13 @@ import * as sinon from 'sinon';
import uuid from 'uuid'; import uuid from 'uuid';
import { ChatMessage } from '../../../session/messages/outgoing'; 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 { PendingMessageCache } from '../../../session/sending/PendingMessageCache';
import { RawMessage } from '../../../session/types/RawMessage'; import { RawMessage } from '../../../session/types/RawMessage';
import { PubKey } from '../../../session/types';
import * as Data from '../../../../js/modules/data';
describe('PendingMessageCache', () => { describe('PendingMessageCache', () => {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
@ -13,34 +17,26 @@ describe('PendingMessageCache', () => {
// tslint:disable-next-line: promise-function-async // tslint:disable-next-line: promise-function-async
const wrapInPromise = (value: any) => const wrapInPromise = (value: any) =>
new Promise(r => { new Promise(resolve => {
r(value); resolve(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,
}); });
};
beforeEach(async () => { beforeEach(async () => {
const mockStorageObject = wrapInPromise([] as Array<RawMessage>);
const voidPromise = wrapInPromise(undefined);
// Stub out methods which touch the database. // Stub out methods which touch the database
sandbox const storageID = 'pendingMessages';
.stub(PendingMessageCache.prototype, 'getFromStorage') let data: Data.StorageItem = {
.returns(mockStorageObject); id: storageID,
sandbox value: '',
.stub(PendingMessageCache.prototype, 'syncCacheWithDB') };
.returns(voidPromise);
TestUtils.stubData('getItemById').withArgs('pendingMessages').callsFake(async () => {
return wrapInPromise(data);
});
TestUtils.stubData('createOrUpdateItem').callsFake((item: Data.StorageItem) => {
data = item;
});
// Initialize new stubbed cache // Initialize new stubbed cache
pendingMessageCacheStub = new PendingMessageCache(); pendingMessageCacheStub = new PendingMessageCache();
@ -60,8 +56,8 @@ describe('PendingMessageCache', () => {
}); });
it('can add to cache', async () => { it('can add to cache', async () => {
const device = PubKey.generate(); const device = PubKey.generateFake();
const message = generateUniqueMessage(); const message = MessageUtils.generateUniqueChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message); const rawMessage = MessageUtils.toRawMessage(device, message);
await pendingMessageCacheStub.add(device, message); await pendingMessageCacheStub.add(device, message);
@ -77,8 +73,8 @@ describe('PendingMessageCache', () => {
}); });
it('can remove from cache', async () => { it('can remove from cache', async () => {
const device = PubKey.generate(); const device = PubKey.generateFake();
const message = generateUniqueMessage(); const message = MessageUtils.generateUniqueChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message); const rawMessage = MessageUtils.toRawMessage(device, message);
await pendingMessageCacheStub.add(device, message); await pendingMessageCacheStub.add(device, message);
@ -98,16 +94,16 @@ describe('PendingMessageCache', () => {
it('can get devices', async () => { it('can get devices', async () => {
const cacheItems = [ const cacheItems = [
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
]; ];
@ -130,12 +126,12 @@ describe('PendingMessageCache', () => {
it('can get pending for device', async () => { it('can get pending for device', async () => {
const cacheItems = [ const cacheItems = [
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
]; ];
@ -157,8 +153,8 @@ describe('PendingMessageCache', () => {
}); });
it('can find nothing when empty', async () => { it('can find nothing when empty', async () => {
const device = PubKey.generate(); const device = PubKey.generateFake();
const message = generateUniqueMessage(); const message = MessageUtils.generateUniqueChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message); const rawMessage = MessageUtils.toRawMessage(device, message);
const foundMessage = pendingMessageCacheStub.find(rawMessage); const foundMessage = pendingMessageCacheStub.find(rawMessage);
@ -166,8 +162,8 @@ describe('PendingMessageCache', () => {
}); });
it('can find message in cache', async () => { it('can find message in cache', async () => {
const device = PubKey.generate(); const device = PubKey.generateFake();
const message = generateUniqueMessage(); const message = MessageUtils.generateUniqueChatMessage();
const rawMessage = MessageUtils.toRawMessage(device, message); const rawMessage = MessageUtils.toRawMessage(device, message);
await pendingMessageCacheStub.add(device, message); await pendingMessageCacheStub.add(device, message);
@ -183,16 +179,16 @@ describe('PendingMessageCache', () => {
it('can clear cache', async () => { it('can clear cache', async () => {
const cacheItems = [ const cacheItems = [
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
{ {
device: PubKey.generate(), device: PubKey.generateFake(),
message: generateUniqueMessage(), message: MessageUtils.generateUniqueChatMessage(),
}, },
]; ];

Loading…
Cancel
Save