add a cache of the keypairs for a closed group

pull/1783/head
Audric Ackermann 4 years ago
parent 7cc7db5d4a
commit 9a302fb5ff
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -103,7 +103,6 @@ module.exports = {
getAllEncryptionKeyPairsForGroup, getAllEncryptionKeyPairsForGroup,
getLatestClosedGroupEncryptionKeyPair, getLatestClosedGroupEncryptionKeyPair,
addClosedGroupEncryptionKeyPair, addClosedGroupEncryptionKeyPair,
isKeyPairAlreadySaved,
removeAllClosedGroupEncryptionKeyPairs, removeAllClosedGroupEncryptionKeyPairs,
// open group v2 // open group v2
@ -1804,8 +1803,6 @@ function saveMessage(data) {
unread, unread,
}; };
console.warn('payload: ', payload);
globalInstance globalInstance
.prepare( .prepare(
`INSERT OR REPLACE INTO ${MESSAGES_TABLE} ( `INSERT OR REPLACE INTO ${MESSAGES_TABLE} (
@ -2692,16 +2689,6 @@ function addClosedGroupEncryptionKeyPair(groupPublicKey, keypair, instance) {
}); });
} }
function isKeyPairAlreadySaved(
groupPublicKey,
newKeyPairInHex // : HexKeyPair
) {
const allKeyPairs = getAllEncryptionKeyPairsForGroup(groupPublicKey);
return (allKeyPairs || []).some(
k => newKeyPairInHex.publicHex === k.publicHex && newKeyPairInHex.privateHex === k.privateHex
);
}
function removeAllClosedGroupEncryptionKeyPairs(groupPublicKey) { function removeAllClosedGroupEncryptionKeyPairs(groupPublicKey) {
globalInstance globalInstance
.prepare( .prepare(

@ -6,7 +6,7 @@ import { Emojify } from './Emojify';
type Props = { type Props = {
phoneNumber: string; phoneNumber: string;
name?: string | null; name?: string | null;
profileName?: string; profileName?: string | null;
module?: string; module?: string;
boldProfileName?: Boolean; boldProfileName?: Boolean;
compact?: Boolean; compact?: Boolean;

@ -154,7 +154,6 @@ const channelsToMake = {
getAllEncryptionKeyPairsForGroup, getAllEncryptionKeyPairsForGroup,
getLatestClosedGroupEncryptionKeyPair, getLatestClosedGroupEncryptionKeyPair,
addClosedGroupEncryptionKeyPair, addClosedGroupEncryptionKeyPair,
isKeyPairAlreadySaved,
removeAllClosedGroupEncryptionKeyPairs, removeAllClosedGroupEncryptionKeyPairs,
removeOneOpenGroupV1Message, removeOneOpenGroupV1Message,
@ -497,13 +496,6 @@ export async function addClosedGroupEncryptionKeyPair(
await channels.addClosedGroupEncryptionKeyPair(groupPublicKey, keypair); await channels.addClosedGroupEncryptionKeyPair(groupPublicKey, keypair);
} }
export async function isKeyPairAlreadySaved(
groupPublicKey: string,
keypair: HexKeyPair
): Promise<boolean> {
return channels.isKeyPairAlreadySaved(groupPublicKey, keypair);
}
export async function removeAllClosedGroupEncryptionKeyPairs( export async function removeAllClosedGroupEncryptionKeyPairs(
groupPublicKey: string groupPublicKey: string
): Promise<void> { ): Promise<void> {

@ -193,9 +193,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
trailing: true, trailing: true,
leading: true, leading: true,
}); });
this.triggerUIRefresh = _.throttle(this.triggerUIRefresh, 1000, { this.triggerUIRefresh = _.throttle(this.triggerUIRefresh, 300, {
trailing: true, trailing: true,
leading: true,
}); });
this.throttledNotify = _.debounce(this.notify, 500, { maxWait: 1000, trailing: true }); this.throttledNotify = _.debounce(this.notify, 500, { maxWait: 1000, trailing: true });
//start right away the function is called, and wait 1sec before calling it again //start right away the function is called, and wait 1sec before calling it again
@ -484,7 +483,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return unreadCount; return unreadCount;
} }
public queueJob(callback: any) { public queueJob(callback: () => Promise<void>) {
// tslint:disable-next-line: no-promise-as-boolean // tslint:disable-next-line: no-promise-as-boolean
const previous = this.pending || Promise.resolve(); const previous = this.pending || Promise.resolve();

@ -16,7 +16,6 @@ import {
addClosedGroupEncryptionKeyPair, addClosedGroupEncryptionKeyPair,
getAllEncryptionKeyPairsForGroup, getAllEncryptionKeyPairsForGroup,
getLatestClosedGroupEncryptionKeyPair, getLatestClosedGroupEncryptionKeyPair,
isKeyPairAlreadySaved,
removeAllClosedGroupEncryptionKeyPairs, removeAllClosedGroupEncryptionKeyPairs,
} from '../../ts/data/data'; } from '../../ts/data/data';
import { import {
@ -40,6 +39,52 @@ import { updateConfirmModal } from '../state/ducks/modalDialog';
export const distributingClosedGroupEncryptionKeyPairs = new Map<string, ECKeyPair>(); export const distributingClosedGroupEncryptionKeyPairs = new Map<string, ECKeyPair>();
// this is a cache of the keypairs stored in the db.
const cacheOfClosedGroupKeyPairs: Map<string, Array<HexKeyPair>> = new Map();
export async function getAllCachedECKeyPair(groupPubKey: string) {
let keyPairsFound = cacheOfClosedGroupKeyPairs.get(groupPubKey);
if (!keyPairsFound) {
keyPairsFound = (await getAllEncryptionKeyPairsForGroup(groupPubKey)) || [];
cacheOfClosedGroupKeyPairs.set(groupPubKey, keyPairsFound);
}
return keyPairsFound;
}
/**
*
* @returns true if this keypair was not already saved for this publickey
*/
export async function addKeyPairToCacheAndDBIfNeeded(
groupPubKey: string,
keyPair: HexKeyPair
): Promise<boolean> {
const existingKeyPairs = await getAllCachedECKeyPair(groupPubKey);
const alreadySaved = existingKeyPairs.some(k => {
return k.privateHex === keyPair.privateHex && k.publicHex === keyPair.publicHex;
});
if (alreadySaved) {
return false;
}
await addClosedGroupEncryptionKeyPair(groupPubKey, keyPair);
if (!cacheOfClosedGroupKeyPairs.has(groupPubKey)) {
cacheOfClosedGroupKeyPairs.set(groupPubKey, []);
}
cacheOfClosedGroupKeyPairs.get(groupPubKey)?.push(keyPair);
return true;
}
export async function innerRemoveAllClosedGroupEncryptionKeyPairs(groupPubKey: string) {
cacheOfClosedGroupKeyPairs.set(groupPubKey, []);
await removeAllClosedGroupEncryptionKeyPairs(groupPubKey);
}
export async function handleClosedGroupControlMessage( export async function handleClosedGroupControlMessage(
envelope: EnvelopePlus, envelope: EnvelopePlus,
groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage
@ -199,7 +244,7 @@ export async function handleNewClosedGroup(
encryptionKeyPair!.publicKey, encryptionKeyPair!.publicKey,
encryptionKeyPair!.privateKey encryptionKeyPair!.privateKey
); );
const isKeyPairAlreadyHere = await isKeyPairAlreadySaved( const isKeyPairAlreadyHere = await addKeyPairToCacheAndDBIfNeeded(
groupId, groupId,
ecKeyPairAlreadyExistingConvo.toHexKeyPair() ecKeyPairAlreadyExistingConvo.toHexKeyPair()
); );
@ -207,15 +252,12 @@ export async function handleNewClosedGroup(
await maybeConvo.updateExpirationTimer(expireTimer, sender, Date.now()); await maybeConvo.updateExpirationTimer(expireTimer, sender, Date.now());
if (isKeyPairAlreadyHere) { if (isKeyPairAlreadyHere) {
await getAllEncryptionKeyPairsForGroup(groupId);
window.log.info('Dropping already saved keypair for group', groupId); window.log.info('Dropping already saved keypair for group', groupId);
await removeFromCache(envelope); await removeFromCache(envelope);
return; return;
} }
window.log.info(`Received the encryptionKeyPair for new group ${groupId}`); window.log.info(`Received the encryptionKeyPair for new group ${groupId}`);
await addClosedGroupEncryptionKeyPair(groupId, ecKeyPairAlreadyExistingConvo.toHexKeyPair());
await removeFromCache(envelope); await removeFromCache(envelope);
window.log.warn( window.log.warn(
'Closed group message of type NEW: the conversation already exists, but we saved the new encryption keypair' 'Closed group message of type NEW: the conversation already exists, but we saved the new encryption keypair'
@ -272,7 +314,7 @@ export async function handleNewClosedGroup(
const ecKeyPair = new ECKeyPair(encryptionKeyPair!.publicKey, encryptionKeyPair!.privateKey); const ecKeyPair = new ECKeyPair(encryptionKeyPair!.publicKey, encryptionKeyPair!.privateKey);
window?.log?.info(`Received the encryptionKeyPair for new group ${groupId}`); window?.log?.info(`Received the encryptionKeyPair for new group ${groupId}`);
await addClosedGroupEncryptionKeyPair(groupId, ecKeyPair.toHexKeyPair()); await addKeyPairToCacheAndDBIfNeeded(groupId, ecKeyPair.toHexKeyPair());
// start polling for this new group // start polling for this new group
getSwarmPollingInstance().addGroupId(PubKey.cast(groupId)); getSwarmPollingInstance().addGroupId(PubKey.cast(groupId));
@ -291,7 +333,7 @@ export async function markGroupAsLeftOrKicked(
groupConvo: ConversationModel, groupConvo: ConversationModel,
isKicked: boolean isKicked: boolean
) { ) {
await removeAllClosedGroupEncryptionKeyPairs(groupPublicKey); await innerRemoveAllClosedGroupEncryptionKeyPairs(groupPublicKey);
if (isKicked) { if (isKicked) {
groupConvo.set('isKickedFromGroup', true); groupConvo.set('isKickedFromGroup', true);
@ -408,17 +450,17 @@ async function handleClosedGroupEncryptionKeyPair(
// Store it if needed // Store it if needed
const newKeyPairInHex = keyPair.toHexKeyPair(); const newKeyPairInHex = keyPair.toHexKeyPair();
const isKeyPairAlreadyHere = await isKeyPairAlreadySaved(groupPublicKey, newKeyPairInHex); const isKeyPairAlreadyHere = await addKeyPairToCacheAndDBIfNeeded(
groupPublicKey,
newKeyPairInHex
);
if (isKeyPairAlreadyHere) { if (isKeyPairAlreadyHere) {
const existingKeyPairs = await getAllEncryptionKeyPairsForGroup(groupPublicKey);
window?.log?.info('Dropping already saved keypair for group', groupPublicKey); window?.log?.info('Dropping already saved keypair for group', groupPublicKey);
await removeFromCache(envelope); await removeFromCache(envelope);
return; return;
} }
window?.log?.info('Got a new encryption keypair for group', groupPublicKey); window?.log?.info('Got a new encryption keypair for group', groupPublicKey);
await addClosedGroupEncryptionKeyPair(groupPublicKey, keyPair.toHexKeyPair());
await removeFromCache(envelope); await removeFromCache(envelope);
// trigger decrypting of all this group messages we did not decrypt successfully yet. // trigger decrypting of all this group messages we did not decrypt successfully yet.
await queueAllCachedFromSource(groupPublicKey); await queueAllCachedFromSource(groupPublicKey);
@ -893,12 +935,9 @@ export async function createClosedGroup(groupName: string, members: Array<string
if (allInvitesSent) { if (allInvitesSent) {
const newHexKeypair = encryptionKeyPair.toHexKeyPair(); const newHexKeypair = encryptionKeyPair.toHexKeyPair();
const isHexKeyPairSaved = await isKeyPairAlreadySaved(groupPublicKey, newHexKeypair); const isHexKeyPairSaved = await addKeyPairToCacheAndDBIfNeeded(groupPublicKey, newHexKeypair);
if (!isHexKeyPairSaved) { if (isHexKeyPairSaved) {
// tslint:disable-next-line: no-non-null-assertion
await addClosedGroupEncryptionKeyPair(groupPublicKey, encryptionKeyPair.toHexKeyPair());
} else {
window?.log?.info('Dropping already saved keypair for group', groupPublicKey); window?.log?.info('Dropping already saved keypair for group', groupPublicKey);
} }

@ -11,12 +11,12 @@ import { GroupUtils, UserUtils } from '../session/utils';
import { fromHexToArray, toHex } from '../session/utils/String'; import { fromHexToArray, toHex } from '../session/utils/String';
import { concatUInt8Array, getSodium } from '../session/crypto'; import { concatUInt8Array, getSodium } from '../session/crypto';
import { getConversationController } from '../session/conversations'; import { getConversationController } from '../session/conversations';
import { getAllEncryptionKeyPairsForGroup } from '../../ts/data/data'; import { ECKeyPair, HexKeyPair } from './keypairs';
import { ECKeyPair } from './keypairs';
import { handleConfigurationMessage } from './configMessage'; import { handleConfigurationMessage } from './configMessage';
import { ConversationTypeEnum } from '../models/conversation'; import { ConversationTypeEnum } from '../models/conversation';
import { removeMessagePadding } from '../session/crypto/BufferPadding'; import { removeMessagePadding } from '../session/crypto/BufferPadding';
import { perfEnd, perfStart } from '../session/utils/Performance'; import { perfEnd, perfStart } from '../session/utils/Performance';
import { getAllCachedECKeyPair } from './closedGroups';
export async function handleContentMessage(envelope: EnvelopePlus) { export async function handleContentMessage(envelope: EnvelopePlus) {
try { try {
@ -43,7 +43,11 @@ async function decryptForClosedGroup(envelope: EnvelopePlus, ciphertext: ArrayBu
window?.log?.warn('received medium group message but not for an existing medium group'); window?.log?.warn('received medium group message but not for an existing medium group');
throw new Error('Invalid group public key'); // invalidGroupPublicKey throw new Error('Invalid group public key'); // invalidGroupPublicKey
} }
const encryptionKeyPairs = await getAllEncryptionKeyPairsForGroup(hexEncodedGroupPublicKey); console.time('getAllEncryptionKeyPairsForGroup');
const encryptionKeyPairs = await getAllCachedECKeyPair(hexEncodedGroupPublicKey);
console.timeEnd('getAllEncryptionKeyPairsForGroup');
const encryptionKeyPairsCount = encryptionKeyPairs?.length; const encryptionKeyPairsCount = encryptionKeyPairs?.length;
if (!encryptionKeyPairs?.length) { if (!encryptionKeyPairs?.length) {
throw new Error(`No group keypairs for group ${hexEncodedGroupPublicKey}`); // noGroupKeyPair throw new Error(`No group keypairs for group ${hexEncodedGroupPublicKey}`); // noGroupKeyPair

@ -590,8 +590,6 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
// if the message is `sent` (from secondary device) we have to set the sender manually... (at least for now) // if the message is `sent` (from secondary device) we have to set the sender manually... (at least for now)
source = source || msg.get('source'); source = source || msg.get('source');
const isOurDevice = UserUtils.isUsFromCache(source);
// Conversation Id is: // Conversation Id is:
// - primarySource if it is an incoming DM message, // - primarySource if it is an incoming DM message,
// - destination if it is an outgoing message, // - destination if it is an outgoing message,

@ -21,6 +21,7 @@ import { MessageModel } from '../../models/message';
import { MessageModelType } from '../../models/messageType'; import { MessageModelType } from '../../models/messageType';
import { getMessageController } from '../messages'; import { getMessageController } from '../messages';
import { import {
addKeyPairToCacheAndDBIfNeeded,
distributingClosedGroupEncryptionKeyPairs, distributingClosedGroupEncryptionKeyPairs,
markGroupAsLeftOrKicked, markGroupAsLeftOrKicked,
} from '../../receiver/closedGroups'; } from '../../receiver/closedGroups';
@ -504,7 +505,7 @@ async function generateAndSendNewEncryptionKeyPair(
distributingClosedGroupEncryptionKeyPairs.delete(toHex(groupId)); distributingClosedGroupEncryptionKeyPairs.delete(toHex(groupId));
await addClosedGroupEncryptionKeyPair(toHex(groupId), newKeyPair.toHexKeyPair()); await addKeyPairToCacheAndDBIfNeeded(toHex(groupId), newKeyPair.toHexKeyPair());
}; };
// this is to be sent to the group pubkey adress // this is to be sent to the group pubkey adress
await getMessageQueue().sendToGroup(keypairsMessage, messageSentCallback); await getMessageQueue().sendToGroup(keypairsMessage, messageSentCallback);

@ -35,7 +35,7 @@ export async function send(
encryption encryption
); );
const envelope = await buildEnvelope(envelopeType, device.key, timestamp, cipherText); const envelope = await buildEnvelope(envelopeType, device.key, timestamp, cipherText);
window?.log?.debug('Sending envelope', envelope, ' to ', device.key); window?.log?.debug('Sending envelope with timestamp: ', envelope.timestamp, ' to ', device.key);
const data = wrapEnvelope(envelope); const data = wrapEnvelope(envelope);
return pRetry( return pRetry(

Loading…
Cancel
Save