pull/1159/head
Vincent 5 years ago
parent bbfa6499e0
commit afcbf7049e

@ -97,7 +97,7 @@ export class LeftPaneMessageSection extends React.Component<Props, any> {
if (conversationList !== undefined) {
conversationList = conversationList.filter(
conversation =>
!conversation.isPendingFriendRequest && !conversation.isSecondary
!conversation.isSecondary && !conversation.isPendingFriendRequest
);
}

@ -12,7 +12,5 @@ export abstract class SyncMessage extends ContentMessage {
});
}
protected syncProto(): SignalService.SyncMessage {
return new SignalService.SyncMessage({});
}
protected abstract syncProto(): SignalService.SyncMessage;
}

@ -1,251 +0,0 @@
import { SessionResetMessage } from '../messages/outgoing';
// import { MessageSender } from '../sending';
interface StringToNumberMap {
[key: string]: number;
}
/**
* This map olds the sent session timestamps, i.e. session requests message effectively sent to the recipient.
* It is backed by a database entry so it's loaded from db on startup.
* This map should not be used directly, but instead through
* `_updateSendSessionTimestamp()`, `_getSendSessionRequest()` or `_hasSendSessionRequest()`
*/
let sentSessionsTimestamp: StringToNumberMap;
/**
* This map olds the processed session timestamps, i.e. when we received a session request and handled it.
* It is backed by a database entry so it's loaded from db on startup.
* This map should not be used directly, but instead through
* `_updateProcessedSessionTimestamp()`, `_getProcessedSessionRequest()` or `_hasProcessedSessionRequest()`
*/
let processedSessionsTimestamp: StringToNumberMap;
/**
* This map olds the timestamp on which a sent session reset is triggered for a specific device.
* Once the message is sent or failed to sent, this device is removed from here.
* This is a memory only map. Which means that on app restart it's starts empty.
*/
const pendingSendSessionsTimestamp: Set<string> = new Set();
/** ======= exported functions ======= */
/** Returns true if we already have a session with that device */
export async function hasSession(device: string): Promise<boolean> {
// Session does not use the concept of a deviceId, thus it's always 1
const address = new window.libsignal.SignalProtocolAddress(device, 1);
const sessionCipher = new window.libsignal.SessionCipher(
window.textsecure.storage.protocol,
address
);
return sessionCipher.hasOpenSession();
}
/**
* 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.
*/
export async function hasSentSessionRequest(device: string): Promise<boolean> {
const pendingSend = pendingSendSessionsTimestamp.has(device);
const hasSent = await _hasSentSessionRequest(device);
return pendingSend || hasSent;
}
/**
* Triggers a SessionResetMessage to be sent if:
* - we do not already have a session and
* - we did not sent a session request already to that device and
* - we do not have a session request currently being send to that device
*/
export async function sendSessionRequestIfNeeded(
device: string
): Promise<void> {
if (hasSession(device) || hasSentSessionRequest(device)) {
return Promise.resolve();
}
const preKeyBundle = await window.libloki.storage.getPreKeyBundleForContact(
device
);
const sessionReset = new SessionResetMessage({
preKeyBundle,
timestamp: Date.now(),
});
return sendSessionRequests(sessionReset, device);
}
/** */
export async function sendSessionRequests(
message: SessionResetMessage,
device: string
): Promise<void> {
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
pendingSendSessionsTimestamp.add(device);
// const rawMessage = toRawMessage(message);
// // TODO: Send out the request via MessageSender
// return MessageSender.send(rawMessage)
// .then(async () => {
// await _updateSentSessionTimestamp(device, timestamp);
// pendingSendSessionsTimestamp.delete(device);
// })
// .catch(() => {
// pendingSendSessionsTimestamp.delete(device);
// });
}
/**
* Called when a session is establish so we store on database this info.
*/
export async function onSessionEstablished(device: string) {
// remove our existing sent timestamp for that device
return _updateSentSessionTimestamp(device, undefined);
}
export async function shouldProcessSessionRequest(
device: string,
messageTimestamp: number
): Promise<boolean> {
const existingSentTimestamp = (await _getSentSessionRequest(device)) || 0;
const existingProcessedTimestamp =
(await _getProcessedSessionRequest(device)) || 0;
return (
messageTimestamp > existingSentTimestamp &&
messageTimestamp > existingProcessedTimestamp
);
}
export async function onSessionRequestProcessed(device: string) {
return _updateProcessedSessionTimestamp(device, Date.now());
}
/** ======= local / utility functions ======= */
/**
* We only need to fetch once from the database, because we are the only one writing to it
*/
async function _fetchFromDBIfNeeded(): Promise<void> {
if (!sentSessionsTimestamp) {
const sentItem = await window.Signal.Data.getItemById(
'sentSessionsTimestamp'
);
if (sentItem) {
sentSessionsTimestamp = sentItem.value;
} else {
sentSessionsTimestamp = {};
}
const processedItem = await window.Signal.Data.getItemById(
'processedSessionsTimestamp'
);
if (processedItem) {
processedSessionsTimestamp = processedItem.value;
} else {
processedSessionsTimestamp = {};
}
}
}
async function _writeToDBSentSessions(): Promise<void> {
const data = {
id: 'sentSessionsTimestamp',
value: JSON.stringify(sentSessionsTimestamp),
};
await window.Signal.Data.createOrUpdateItem(data);
}
async function _writeToDBProcessedSessions(): Promise<void> {
const data = {
id: 'processedSessionsTimestamp',
value: JSON.stringify(processedSessionsTimestamp),
};
await window.Signal.Data.createOrUpdateItem(data);
}
/**
* This is a utility function to avoid duplicated code of _updateSentSessionTimestamp and _updateProcessedSessionTimestamp
*/
async function _updateSessionTimestamp(
device: string,
timestamp: number | undefined,
map: StringToNumberMap
): Promise<boolean> {
await _fetchFromDBIfNeeded();
if (!timestamp) {
if (!!map[device]) {
delete map.device;
return true;
}
return false;
}
map[device] = timestamp;
return true;
}
/**
*
* @param device the device id
* @param timestamp undefined to remove the key/value pair, otherwise updates the sent timestamp and write to DB
*/
async function _updateSentSessionTimestamp(
device: string,
timestamp: number | undefined
): Promise<void> {
if (_updateSessionTimestamp(device, timestamp, sentSessionsTimestamp)) {
await _writeToDBSentSessions();
}
}
/**
* timestamp undefined to remove the key/value pair, otherwise updates the processed timestamp and writes to DB
*/
async function _updateProcessedSessionTimestamp(
device: string,
timestamp: number | undefined
): Promise<void> {
if (_updateSessionTimestamp(device, timestamp, processedSessionsTimestamp)) {
await _writeToDBProcessedSessions();
}
}
/**
* This is a utility function to avoid duplicate code between `_getProcessedSessionRequest()` and `_getSentSessionRequest()`
*/
async function _getSessionRequest(
device: string,
map: StringToNumberMap
): Promise<number | undefined> {
await _fetchFromDBIfNeeded();
return map[device];
}
async function _getSentSessionRequest(
device: string
): Promise<number | undefined> {
return _getSessionRequest(device, sentSessionsTimestamp);
}
async function _getProcessedSessionRequest(
device: string
): Promise<number | undefined> {
return _getSessionRequest(device, processedSessionsTimestamp);
}
async function _hasSentSessionRequest(device: string): Promise<boolean> {
await _fetchFromDBIfNeeded();
return !!sentSessionsTimestamp[device];
}

@ -1,9 +1,9 @@
import * as crypto from 'crypto';
export class PubKey {
private static readonly PUBKEY_LEN = 66;
private static readonly regex: string = `^05[0-9a-fA-F]{${PubKey.PUBKEY_LEN - 2}}$`;
private static readonly regex: string = `^05[0-9a-fA-F]{${PubKey.PUBKEY_LEN -
2}}$`;
public readonly key: string;
constructor(pubkeyString: string) {
@ -30,7 +30,7 @@ export class PubKey {
public static generateFake(): PubKey {
// Generates a mock pubkey for testing
const numBytes = (PubKey.PUBKEY_LEN / 2) - 1;
const numBytes = PubKey.PUBKEY_LEN / 2 - 1;
const hexBuffer = crypto.randomBytes(numBytes).toString('hex');
const pubkeyString = `05${hexBuffer}`;

@ -1,33 +1,17 @@
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';
import { EncryptionType, PubKey } from '../types';
export function toRawMessage(device: PubKey, message: ContentMessage): RawMessage {
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,

@ -1,9 +0,0 @@
// import { expect } from 'chai';
// import { SessionProtocol } from '../../../session/protocols';
// describe('SessionProtocol', () => {
// it('has ', () => {
// });
// });

@ -1,21 +1,18 @@
import { expect } from 'chai';
import * as sinon from 'sinon';
import uuid from 'uuid';
import * as MessageUtils from '../../../session/utils';
import { TestUtils } from '../../../test/test-utils';
import { PendingMessageCache } from '../../../session/sending/PendingMessageCache';
import { PubKey } from '../../../session/types';
// Equivalent to Data.StorageItem
interface StorageItem {
id: string;
value: any;
}
describe('PendingMessageCache', () => {// Initialize new stubbed cache
describe('PendingMessageCache', () => {
// Initialize new stubbed cache
let pendingMessageCacheStub: PendingMessageCache;
beforeEach(async () => {
@ -26,7 +23,9 @@ describe('PendingMessageCache', () => {// Initialize new stubbed cache
value: '',
};
TestUtils.stubData('getItemById').withArgs('pendingMessages').callsFake(async () => {
TestUtils.stubData('getItemById')
.withArgs('pendingMessages')
.callsFake(async () => {
return data;
});
@ -36,7 +35,6 @@ describe('PendingMessageCache', () => {// Initialize new stubbed cache
pendingMessageCacheStub = new PendingMessageCache();
await pendingMessageCacheStub.init();
});
afterEach(() => {

Loading…
Cancel
Save