diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index 1b87af67d..845b60b34 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -12,7 +12,11 @@ import { GroupUtils, UserUtils } from '../session/utils'; import { fromHexToArray, toHex } from '../session/utils/String'; import { concatUInt8Array, getSodium } from '../session/crypto'; import { ConversationController } from '../session/conversations'; -import { getAllEncryptionKeyPairsForGroup } from '../../js/modules/data'; +import { + createOrUpdateItem, + getAllEncryptionKeyPairsForGroup, + getItemById, +} from '../../js/modules/data'; import { ECKeyPair } from './keypairs'; import { handleNewClosedGroup } from './closedGroups'; import { KeyPairRequestManager } from './keyPairRequestManager'; @@ -519,7 +523,7 @@ async function handleTypingMessage( } } -async function handleConfigurationMessage( +export async function handleConfigurationMessage( envelope: EnvelopePlus, configurationMessage: SignalService.ConfigurationMessage ): Promise { @@ -527,15 +531,35 @@ async function handleConfigurationMessage( if (!ourPubkey) { return; } - + console.warn('ourPubkey', ourPubkey); + console.warn('envelope.source', envelope.source); if (envelope.source !== ourPubkey) { - window.log.info('dropping configuration change from someone else than us.'); + window?.log?.info( + 'Dropping configuration change from someone else than us.' + ); return removeFromCache(envelope); } + const ITEM_ID_PROCESSED_CONFIGURATION_MESSAGE = + 'ITEM_ID_PROCESSED_CONFIGURATION_MESSAGE'; + const didWeHandleAConfigurationMessageAlready = + (await getItemById(ITEM_ID_PROCESSED_CONFIGURATION_MESSAGE))?.value || + false; + if (didWeHandleAConfigurationMessageAlready) { + window?.log?.warn( + 'Dropping configuration change as we already handled one... ' + ); + await removeFromCache(envelope); + return; + } + await createOrUpdateItem({ + id: ITEM_ID_PROCESSED_CONFIGURATION_MESSAGE, + value: true, + }); + const numberClosedGroup = configurationMessage.closedGroups?.length || 0; - window.log.warn( + window?.log?.warn( `Received ${numberClosedGroup} closed group on configuration. Creating them... ` ); @@ -551,7 +575,13 @@ async function handleConfigurationMessage( publicKey: c.publicKey, } ); - await handleNewClosedGroup(envelope, groupUpdate); + try { + await handleNewClosedGroup(envelope, groupUpdate); + } catch (e) { + window?.log?.warn( + 'failed to handle a new closed group from configuration message' + ); + } }) ); @@ -563,7 +593,7 @@ async function handleConfigurationMessage( for (let i = 0; i < numberOpenGroup; i++) { const current = configurationMessage.openGroups[i]; if (!allOpenGroups.includes(current)) { - window.log.info( + window?.log?.info( `triggering join of public chat '${current}' from ConfigurationMessage` ); void OpenGroup.join(current); diff --git a/ts/test/session/unit/messages/ConfigurationMessage_test.ts b/ts/test/session/unit/messages/ConfigurationMessage_test.ts index 8ceb988fb..04555f9c6 100644 --- a/ts/test/session/unit/messages/ConfigurationMessage_test.ts +++ b/ts/test/session/unit/messages/ConfigurationMessage_test.ts @@ -5,7 +5,6 @@ import { ConfigurationMessage, ConfigurationMessageClosedGroup, } from '../../../../session/messages/outgoing/content/ConfigurationMessage'; -import { PubKey } from '../../../../session/types'; import { TestUtils } from '../../../test-utils'; describe('ConfigurationMessage', () => { diff --git a/ts/test/session/unit/receiving/ConfigurationMessage_test.ts b/ts/test/session/unit/receiving/ConfigurationMessage_test.ts new file mode 100644 index 000000000..0589ff1fc --- /dev/null +++ b/ts/test/session/unit/receiving/ConfigurationMessage_test.ts @@ -0,0 +1,93 @@ +import { SignalService } from '../../../../protobuf'; +import { handleConfigurationMessage } from '../../../../receiver/contentMessage'; +import chai from 'chai'; + +import { ConfigurationMessage } from '../../../../session/messages/outgoing/content/ConfigurationMessage'; +import { UserUtils } from '../../../../session/utils'; +import { TestUtils } from '../../../test-utils'; + +import Sinon, * as sinon from 'sinon'; +import * as cache from '../../../../receiver/cache'; +import * as data from '../../../../../js/modules/data'; +import { EnvelopePlus } from '../../../../receiver/types'; + +// tslint:disable-next-line: no-require-imports no-var-requires +const chaiAsPromised = require('chai-as-promised'); +chai.use(chaiAsPromised); +chai.should(); + +const { expect } = chai; + +describe('ConfigurationMessage_receiving', () => { + const sandbox = sinon.createSandbox(); + let createOrUpdateStub: Sinon.SinonStub; + let getItemByIdStub: Sinon.SinonStub; + let sender: string; + + let envelope: EnvelopePlus; + let config: ConfigurationMessage; + + beforeEach(() => { + sandbox.stub(cache, 'removeFromCache').resolves(); + sender = TestUtils.generateFakePubKey().key; + config = new ConfigurationMessage({ + activeOpenGroups: [], + activeClosedGroups: [], + timestamp: Date.now(), + identifier: 'whatever', + }); + }); + + afterEach(() => { + TestUtils.restoreStubs(); + sandbox.restore(); + }); + + it('should not be processed if we do not have a pubkey', async () => { + sandbox.stub(UserUtils, 'getCurrentDevicePubKey').resolves(undefined); + envelope = TestUtils.generateEnvelopePlus(sender); + + const proto = config.contentProto(); + createOrUpdateStub = sandbox.stub(data, 'createOrUpdateItem').resolves(); + getItemByIdStub = sandbox.stub(data, 'getItemById').resolves(); + await handleConfigurationMessage( + envelope, + proto.configurationMessage as SignalService.ConfigurationMessage + ); + expect(createOrUpdateStub.callCount).to.equal(0); + expect(getItemByIdStub.callCount).to.equal(0); + }); + + describe('with ourNumber set', () => { + const ourNumber = TestUtils.generateFakePubKey().key; + + beforeEach(() => { + sandbox.stub(UserUtils, 'getCurrentDevicePubKey').resolves(ourNumber); + }); + + it('should not be processed if the message is not coming from our number', async () => { + const proto = config.contentProto(); + // sender !== ourNumber + envelope = TestUtils.generateEnvelopePlus(sender); + + createOrUpdateStub = sandbox.stub(data, 'createOrUpdateItem').resolves(); + getItemByIdStub = sandbox.stub(data, 'getItemById').resolves(); + await handleConfigurationMessage( + envelope, + proto.configurationMessage as SignalService.ConfigurationMessage + ); + expect(createOrUpdateStub.callCount).to.equal(0); + expect(getItemByIdStub.callCount).to.equal(0); + }); + + // it('should be processed if the message is coming from our number', async () => { + // const proto = config.contentProto(); + // envelope = TestUtils.generateEnvelopePlus(ourNumber); + + // createOrUpdateStub = sandbox.stub(data, 'createOrUpdateItem').resolves(); + // getItemByIdStub = sandbox.stub(data, 'getItemById').resolves(); + // await handleConfigurationMessage(envelope, proto.configurationMessage as SignalService.ConfigurationMessage); + // expect(getItemByIdStub.callCount).to.equal(1); + // }); + }); +}); diff --git a/ts/test/test-utils/utils/envelope.ts b/ts/test/test-utils/utils/envelope.ts index 32690304f..73b59ad4c 100644 --- a/ts/test/test-utils/utils/envelope.ts +++ b/ts/test/test-utils/utils/envelope.ts @@ -22,6 +22,21 @@ export function generateEnvelopePlusClosedGroup( return envelope; } +export function generateEnvelopePlus(sender: string): EnvelopePlus { + const envelope: EnvelopePlus = { + receivedAt: Date.now(), + timestamp: Date.now() - 2000, + id: uuid(), + type: SignalService.Envelope.Type.UNIDENTIFIED_SENDER, + source: sender, + senderIdentity: sender, + content: new Uint8Array(), + toJSON: () => ['fake'], + }; + + return envelope; +} + export function generateGroupUpdateNameChange( groupId: string ): SignalService.DataMessage.ClosedGroupControlMessage {