add the request and reply of an encryptionKeyPair if needed
parent
94a9faec9a
commit
375c5ba1a8
@ -0,0 +1,47 @@
|
||||
import { PubKey } from '../session/types';
|
||||
import { SECONDS } from '../session/utils/Number';
|
||||
|
||||
/**
|
||||
* Singleton handling the logic behing requesting EncryptionKeypair for a closed group we need.
|
||||
*
|
||||
* Nothing is read/written to the db, it's all on memory for now.
|
||||
*/
|
||||
export class KeyPairRequestManager {
|
||||
public static DELAY_BETWEEN_TWO_REQUEST_MS = SECONDS * 30;
|
||||
private static instance: KeyPairRequestManager | null;
|
||||
private readonly requestTimestamps: Map<string, number>;
|
||||
|
||||
private constructor() {
|
||||
this.requestTimestamps = new Map();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (KeyPairRequestManager.instance) {
|
||||
return KeyPairRequestManager.instance;
|
||||
}
|
||||
KeyPairRequestManager.instance = new KeyPairRequestManager();
|
||||
return KeyPairRequestManager.instance;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.requestTimestamps.clear();
|
||||
}
|
||||
|
||||
public markRequestSendFor(pubkey: PubKey, timestamp: number) {
|
||||
this.requestTimestamps.set(pubkey.key, timestamp);
|
||||
}
|
||||
|
||||
public get(pubkey: PubKey) {
|
||||
return this.requestTimestamps.get(pubkey.key);
|
||||
}
|
||||
|
||||
public canTriggerRequestWith(pubkey: PubKey) {
|
||||
const record = this.requestTimestamps.get(pubkey.key);
|
||||
if (!record) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
return now - record >= KeyPairRequestManager.DELAY_BETWEEN_TWO_REQUEST_MS;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { fromHexToArray } from '../../../../../utils/String';
|
||||
import { ClosedGroupEncryptionPairMessage } from './ClosedGroupEncryptionPairMessage';
|
||||
|
||||
/**
|
||||
* On Desktop, we need separate class for message being sent to a closed group or a private chat.
|
||||
*
|
||||
* This is because we use the class of the message to know what encryption to use.
|
||||
* See toRawMessage();
|
||||
*
|
||||
* This class is just used to let us send the encryption key par after we receivied a ENCRYPTION_KEYPAIR_REQUEST
|
||||
* from a member of a group.
|
||||
* This reply must be sent to this user's pubkey, and so be encoded using sessionProtocol.
|
||||
*/
|
||||
export class ClosedGroupEncryptionPairReplyMessage extends ClosedGroupEncryptionPairMessage {
|
||||
public dataProto(): SignalService.DataMessage {
|
||||
const dataMessage = super.dataProto();
|
||||
// tslint:disable: no-non-null-assertion
|
||||
dataMessage.closedGroupControlMessage!.publicKey = fromHexToArray(
|
||||
this.groupId.key
|
||||
);
|
||||
|
||||
return dataMessage;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import { Constants } from '../../../../..';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { ClosedGroupMessage } from './ClosedGroupMessage';
|
||||
|
||||
export class ClosedGroupEncryptionPairRequestMessage extends ClosedGroupMessage {
|
||||
public dataProto(): SignalService.DataMessage {
|
||||
const dataMessage = super.dataProto();
|
||||
|
||||
// tslint:disable: no-non-null-assertion
|
||||
dataMessage.closedGroupControlMessage!.type =
|
||||
SignalService.DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR_REQUEST;
|
||||
|
||||
return dataMessage;
|
||||
}
|
||||
|
||||
public ttl(): number {
|
||||
return Constants.TTL_DEFAULT.ENCRYPTION_PAIR_GROUP;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
import chai from 'chai';
|
||||
// tslint:disable: no-require-imports no-var-requires no-implicit-dependencies
|
||||
|
||||
import _ from 'lodash';
|
||||
import { describe } from 'mocha';
|
||||
import { KeyPairRequestManager } from '../../../../receiver/keyPairRequestManager';
|
||||
import { TestUtils } from '../../../test-utils';
|
||||
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
chai.should();
|
||||
const { expect } = chai;
|
||||
|
||||
// tslint:disable-next-line: max-func-body-length
|
||||
describe('KeyPairRequestManager', () => {
|
||||
let inst: KeyPairRequestManager;
|
||||
beforeEach(() => {
|
||||
KeyPairRequestManager.getInstance().reset();
|
||||
inst = KeyPairRequestManager.getInstance();
|
||||
});
|
||||
|
||||
it('getInstance() should return an instance', () => {
|
||||
expect(inst).to.exist;
|
||||
});
|
||||
|
||||
describe('markRequestSendFor', () => {
|
||||
it('should be able to set a timestamp for a pubkey', () => {
|
||||
const groupPubkey = TestUtils.generateFakePubKey();
|
||||
const now = Date.now();
|
||||
inst.markRequestSendFor(groupPubkey, now);
|
||||
expect(inst.get(groupPubkey)).to.be.equal(now);
|
||||
});
|
||||
|
||||
it('should be able to override a timestamp for a pubkey', () => {
|
||||
const groupPubkey = TestUtils.generateFakePubKey();
|
||||
const timestamp1 = Date.now();
|
||||
inst.markRequestSendFor(groupPubkey, timestamp1);
|
||||
expect(inst.get(groupPubkey)).to.be.equal(timestamp1);
|
||||
const timestamp2 = Date.now() + 1000;
|
||||
inst.markRequestSendFor(groupPubkey, timestamp2);
|
||||
expect(inst.get(groupPubkey)).to.be.equal(timestamp2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canTriggerRequestWith', () => {
|
||||
it('should return true if there is no timestamp set for this pubkey', () => {
|
||||
const groupPubkey = TestUtils.generateFakePubKey();
|
||||
const can = inst.canTriggerRequestWith(groupPubkey);
|
||||
expect(can).to.be.equal(
|
||||
true,
|
||||
'should return true if we there is no timestamp set for this pubkey'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if there is a timestamp set for this pubkey and it is less than DELAY_BETWEEN_TWO_REQUEST_MS', () => {
|
||||
const groupPubkey = TestUtils.generateFakePubKey();
|
||||
const timestamp1 = Date.now();
|
||||
|
||||
inst.markRequestSendFor(groupPubkey, timestamp1);
|
||||
const can = inst.canTriggerRequestWith(groupPubkey);
|
||||
expect(can).to.be.equal(
|
||||
false,
|
||||
'return false if there is a timestamp set for this pubkey and it is less than DELAY_BETWEEN_TWO_REQUEST_MS'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if there is a timestamp set for this pubkey and it is more than DELAY_BETWEEN_TWO_REQUEST_MS', () => {
|
||||
const groupPubkey = TestUtils.generateFakePubKey();
|
||||
const timestamp1 =
|
||||
Date.now() - KeyPairRequestManager.DELAY_BETWEEN_TWO_REQUEST_MS;
|
||||
|
||||
inst.markRequestSendFor(groupPubkey, timestamp1);
|
||||
const can = inst.canTriggerRequestWith(groupPubkey);
|
||||
expect(can).to.be.equal(
|
||||
true,
|
||||
'true if there is a timestamp set for this pubkey and it is more than DELAY_BETWEEN_TWO_REQUEST_MS'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue