From f26133a5040e8017b573c916f2113b844cf5c73e Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 13 Feb 2025 14:45:08 +1100 Subject: [PATCH 1/3] fix: add sigtimestamp to all content message --- package.json | 2 +- protos/SignalService.proto | 1 + ts/receiver/common.ts | 21 +++ ts/receiver/contentMessage.ts | 6 + ts/receiver/opengroup.ts | 9 ++ .../apis/open_group_api/sogsv3/sogsApiV3.ts | 10 +- .../messages/outgoing/ContentMessage.ts | 19 ++- .../messages/outgoing/ExpirableMessage.ts | 2 +- .../ExpirationTimerUpdateMessage.ts | 7 - .../controlMessage/MessageRequestResponse.ts | 4 +- .../outgoing/controlMessage/TypingMessage.ts | 4 +- .../outgoing/controlMessage/UnsendMessage.ts | 4 +- .../receipt/ReadReceiptMessage.ts | 4 +- ts/session/sending/MessageSentHandler.ts | 4 +- .../shouldProcessMessage_test.ts | 130 ++++++++++++++++++ yarn.lock | 6 +- 16 files changed, 204 insertions(+), 29 deletions(-) create mode 100644 ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts diff --git a/package.json b/package.json index edd312fab..31c1318b6 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "fs-extra": "9.0.0", "glob": "10.3.10", "image-type": "^4.1.0", - "libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz", + "libsession_util_nodejs": "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.17/libsession_util_nodejs-v0.4.17.tar.gz", "libsodium-wrappers-sumo": "^0.7.9", "linkify-it": "^4.0.1", "lodash": "^4.17.21", diff --git a/protos/SignalService.proto b/protos/SignalService.proto index ed9535b50..7631f2551 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -60,6 +60,7 @@ message Content { optional MessageRequestResponse messageRequestResponse = 10; optional ExpirationType expirationType = 12; optional uint32 expirationTimer = 13; + optional uint64 sigTimestamp = 14; } message KeyPair { diff --git a/ts/receiver/common.ts b/ts/receiver/common.ts index b2976622d..6d375f431 100644 --- a/ts/receiver/common.ts +++ b/ts/receiver/common.ts @@ -1,5 +1,7 @@ import { toNumber } from 'lodash'; import { EnvelopePlus } from './types'; +import type { SignalService } from '../protobuf'; +import { DURATION } from '../session/constants'; export function getEnvelopeId(envelope: EnvelopePlus) { if (envelope.source) { @@ -8,3 +10,22 @@ export function getEnvelopeId(envelope: EnvelopePlus) { return envelope.id; } + +export function shouldProcessContentMessage( + envelope: Pick, + content: Pick, + isCommunity: boolean +) { + // FIXME: drop this case once the change has been out in the wild long enough + if (!content.sigTimestamp || !toNumber(content.sigTimestamp)) { + // legacy client + return true; + } + const envelopeTimestamp = toNumber(envelope.timestamp); + const contentTimestamp = toNumber(content.sigTimestamp); + if (!isCommunity) { + return envelopeTimestamp === contentTimestamp; + } + // we want to process a community message and allow a window of 6 hours + return Math.abs(envelopeTimestamp - contentTimestamp) <= 6 * DURATION.HOURS; +} diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index c84f40898..01e854590 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -36,6 +36,7 @@ import { handleCallMessage } from './callMessage'; import { getAllCachedECKeyPair, sentAtMoreRecentThanWrapper } from './closedGroups'; import { ECKeyPair } from './keypairs'; import { CONVERSATION_PRIORITIES, ConversationTypeEnum } from '../models/types'; +import { shouldProcessContentMessage } from './common'; export async function handleSwarmContentMessage( envelope: EnvelopePlus, @@ -480,6 +481,11 @@ export async function innerHandleSwarmContentMessage({ window.log.info('innerHandleSwarmContentMessage'); const content = SignalService.Content.decode(new Uint8Array(contentDecrypted)); + if (!shouldProcessContentMessage(envelope, content, false)) { + window.log.info('innerHandleSwarmContentMessage: dropping invalid content message'); + await IncomingMessageCache.removeFromCache(envelope); + return; + } /** * senderIdentity is set ONLY if that message is a closed group message. diff --git a/ts/receiver/opengroup.ts b/ts/receiver/opengroup.ts index 6ff24ee40..246572dc9 100644 --- a/ts/receiver/opengroup.ts +++ b/ts/receiver/opengroup.ts @@ -14,6 +14,7 @@ import { fromBase64ToArray } from '../session/utils/String'; import { cleanIncomingDataMessage, messageHasVisibleContent } from './dataMessage'; import { handleMessageJob, toRegularMessage } from './queuedJob'; import { OpenGroupRequestCommonType } from '../data/types'; +import { shouldProcessContentMessage } from './common'; export const handleOpenGroupV4Message = async ( message: OpenGroupMessageV4, @@ -52,6 +53,14 @@ const handleOpenGroupMessage = async ( const decodedContent = SignalService.Content.decode(dataUint); + if (!shouldProcessContentMessage({ timestamp: sentTimestamp }, decodedContent, true)) { + window?.log?.info( + 'sogs message: shouldProcessContentMessage is false for message sentAt:', + sentTimestamp + ); + return; + } + const conversationId = getOpenGroupV2ConversationId(serverUrl, roomId); if (!conversationId) { window?.log?.error('We cannot handle a message without a conversationId'); diff --git a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts index 9b63cd47a..7a362aec3 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts @@ -42,6 +42,7 @@ import { sogsRollingDeletions } from './sogsRollingDeletions'; import { processMessagesUsingCache } from './sogsV3MutationCache'; import { OpenGroupRequestCommonType } from '../../../../data/types'; import { ConversationTypeEnum } from '../../../../models/types'; +import { shouldProcessContentMessage } from '../../../../receiver/common'; /** * Get the convo matching those criteria and make sure it is an opengroup convo, or return null. @@ -405,7 +406,13 @@ async function handleInboxOutboxMessages( id: v4(), type: SignalService.Envelope.Type.SESSION_MESSAGE, // this is not right, but we forward an already decrypted envelope so we don't care }; - + const contentDecrypted = SignalService.Content.decode(content); + if (!shouldProcessContentMessage(builtEnvelope, contentDecrypted, true)) { + window.log.warn( + `received inbox/outbox message that did not pass the shouldProcessContentMessage test envelopeTs: ${builtEnvelope.timestamp}` + ); + continue; + } if (isOutbox) { /** * Handling outbox messages needs to skip some of the pipeline. @@ -414,7 +421,6 @@ async function handleInboxOutboxMessages( * We will need this to send new message to that user from our second device. */ const recipient = inboxOutboxItem.recipient; - const contentDecrypted = SignalService.Content.decode(content); // if we already know this user's unblinded pubkey, store the blinded message we sent to that blinded recipient under // the unblinded conversation instead (as we would have merge the blinded one with the other ) diff --git a/ts/session/messages/outgoing/ContentMessage.ts b/ts/session/messages/outgoing/ContentMessage.ts index 4a57b7cf8..cf96fabde 100644 --- a/ts/session/messages/outgoing/ContentMessage.ts +++ b/ts/session/messages/outgoing/ContentMessage.ts @@ -2,14 +2,31 @@ import { SignalService } from '../../../protobuf'; import { TTL_DEFAULT } from '../../constants'; import { Message } from './Message'; +type InstanceKeys = { + // eslint-disable-next-line @typescript-eslint/ban-types + [K in keyof T as T[K] extends Function ? never : K]: T[K]; +}; +type ContentFields = Partial, 'sigTimestamp'>>; + export abstract class ContentMessage extends Message { public plainTextBuffer(): Uint8Array { - return SignalService.Content.encode(this.contentProto()).finish(); + const contentProto = this.contentProto(); + if (!contentProto.sigTimestamp) { + throw new Error('trying to build a ContentMessage without a sig timestamp is unsupported'); + } + return SignalService.Content.encode(contentProto).finish(); } public ttl(): number { return TTL_DEFAULT.CONTENT_MESSAGE; } + public makeContentProto(extra: T) { + return new SignalService.Content({ + sigTimestamp: this.createAtNetworkTimestamp, + ...extra, + }); + } + public abstract contentProto(): SignalService.Content; } diff --git a/ts/session/messages/outgoing/ExpirableMessage.ts b/ts/session/messages/outgoing/ExpirableMessage.ts index a6de8ec14..e35cb456e 100644 --- a/ts/session/messages/outgoing/ExpirableMessage.ts +++ b/ts/session/messages/outgoing/ExpirableMessage.ts @@ -24,7 +24,7 @@ export class ExpirableMessage extends ContentMessage { } public contentProto(): SignalService.Content { - return new SignalService.Content({ + return super.makeContentProto({ // TODO legacy messages support will be removed in a future release expirationType: this.expirationType === 'deleteAfterSend' diff --git a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts index 5fe234ced..48f5e4a0f 100644 --- a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts @@ -30,13 +30,6 @@ export class ExpirationTimerUpdateMessage extends DataMessage { this.syncTarget = params.syncTarget ? PubKey.cast(params.syncTarget).key : undefined; } - public contentProto(): SignalService.Content { - return new SignalService.Content({ - ...super.contentProto(), - dataMessage: this.dataProto(), - }); - } - public dataProto(): SignalService.DataMessage { const data = new SignalService.DataMessage({}); diff --git a/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts b/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts index ddfbf370e..f229256e7 100644 --- a/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts +++ b/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts @@ -26,9 +26,7 @@ export class MessageRequestResponse extends ContentMessage { } public contentProto(): SignalService.Content { - return new SignalService.Content({ - messageRequestResponse: this.messageRequestResponseProto(), - }); + return super.makeContentProto({ messageRequestResponse: this.messageRequestResponseProto() }); } public messageRequestResponseProto(): SignalService.MessageRequestResponse { diff --git a/ts/session/messages/outgoing/controlMessage/TypingMessage.ts b/ts/session/messages/outgoing/controlMessage/TypingMessage.ts index 8b8132b51..fc08cee26 100644 --- a/ts/session/messages/outgoing/controlMessage/TypingMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/TypingMessage.ts @@ -23,9 +23,7 @@ export class TypingMessage extends ContentMessage { } public contentProto(): SignalService.Content { - return new SignalService.Content({ - typingMessage: this.typingProto(), - }); + return super.makeContentProto({ typingMessage: this.typingProto() }); } protected typingProto(): SignalService.TypingMessage { diff --git a/ts/session/messages/outgoing/controlMessage/UnsendMessage.ts b/ts/session/messages/outgoing/controlMessage/UnsendMessage.ts index ca5323f74..5e6feac9a 100644 --- a/ts/session/messages/outgoing/controlMessage/UnsendMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/UnsendMessage.ts @@ -18,9 +18,7 @@ export class UnsendMessage extends ContentMessage { } public contentProto(): SignalService.Content { - return new SignalService.Content({ - unsendMessage: this.unsendProto(), - }); + return super.makeContentProto({ unsendMessage: this.unsendProto() }); } public unsendProto(): SignalService.Unsend { diff --git a/ts/session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage.ts b/ts/session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage.ts index 22770934a..78efc24fe 100644 --- a/ts/session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage.ts @@ -14,9 +14,7 @@ export class ReadReceiptMessage extends ContentMessage { } public contentProto(): SignalService.Content { - return new SignalService.Content({ - receiptMessage: this.receiptProto(), - }); + return super.makeContentProto({ receiptMessage: this.receiptProto() }); } protected receiptProto(): SignalService.ReceiptMessage { diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index 268892876..8d7a2ef5b 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -127,7 +127,7 @@ async function handleSwarmMessageSentSuccess( } } catch (e) { window.log.info( - 'failed to decode content (excpected except if message was for a 1o1 as we need it to send the sync message' + 'failed to decode content (expected except if message was for a 1o1 as we need it to send the sync message' ); } } else if (shouldMarkMessageAsSynced) { @@ -185,7 +185,7 @@ async function handleSwarmMessageSentFailure( expirationStartTimestamp: undefined, }); window.log.warn( - `[handleSwarmMessageSentFailure] Stopping a message from disppearing until we retry the send operation. messageId: ${fetchedMessage.get( + `[handleSwarmMessageSentFailure] Stopping a message from disappearing until we retry the send operation. messageId: ${fetchedMessage.get( 'id' )}` ); diff --git a/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts b/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts new file mode 100644 index 000000000..4e6557fc8 --- /dev/null +++ b/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts @@ -0,0 +1,130 @@ +import { describe } from 'mocha'; +import Sinon from 'sinon'; +import Long from 'long'; +import { expect } from 'chai'; +import { TestUtils } from '../../../../test-utils'; +import { shouldProcessContentMessage } from '../../../../../receiver/common'; +import { DURATION } from '../../../../../session/constants'; + +describe('shouldProcessContentMessage', () => { + let envelopeTs: number; + beforeEach(() => { + TestUtils.stubWindowLog(); + envelopeTs = Math.floor(Date.now() + Math.random() * 1000000); + }); + + afterEach(() => { + Sinon.restore(); + }); + + describe('not a community', () => { + const isCommunity = false; + describe('with sig timestamp', () => { + it('if timestamps match: return true', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs }, + isCommunity + ) + ).to.eq(true); + }); + it('if timestamps do not match: return false', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs + 2 }, + isCommunity + ) + ).to.eq(false); + }); + }); + describe('without sig timestamp', () => { + it('if timestamps match or not: return true', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: undefined as any }, + isCommunity + ) + ).to.eq(true); + expect( + shouldProcessContentMessage({ timestamp: envelopeTs }, { sigTimestamp: 0 }, isCommunity) + ).to.eq(true); + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: Long.fromNumber(0) as any }, + isCommunity + ) + ).to.eq(true); + }); + }); + }); + + describe('a community', () => { + const isCommunity = true; + describe('with sig timestamp', () => { + it('if timestamps roughly match: return true', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs }, // exact match + isCommunity + ) + ).to.eq(true); + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs + 6 * DURATION.HOURS - 1 }, // just below 6h of diff (positive) + isCommunity + ) + ).to.eq(true); + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs - 6 * DURATION.HOURS + 1 }, // just below 6h of diff (negative) + isCommunity + ) + ).to.eq(true); + }); + it('if timestamps do not roughly match: return false', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs + 6 * DURATION.HOURS + 1 }, // just above 6h of diff + isCommunity + ) + ).to.eq(false); + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: envelopeTs - 6 * DURATION.HOURS - 1 }, // just above 6h of diff + isCommunity + ) + ).to.eq(false); + }); + }); + describe('without sig timestamp', () => { + it('if timestamps match or not: return true', async () => { + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: undefined as any }, + isCommunity + ) + ).to.eq(true); + expect( + shouldProcessContentMessage({ timestamp: envelopeTs }, { sigTimestamp: 0 }, isCommunity) + ).to.eq(true); + expect( + shouldProcessContentMessage( + { timestamp: envelopeTs }, + { sigTimestamp: Long.fromNumber(0) as any }, + isCommunity + ) + ).to.eq(true); + }); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 866292a61..60692de40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4944,9 +4944,9 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -"libsession_util_nodejs@https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz": - version "0.4.16" - resolved "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.16/libsession_util_nodejs-v0.4.16.tar.gz#253d4d02388b5bfb41f24c88fae5061b137ca615" +"libsession_util_nodejs@https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.17/libsession_util_nodejs-v0.4.17.tar.gz": + version "0.4.17" + resolved "https://github.com/session-foundation/libsession-util-nodejs/releases/download/v0.4.17/libsession_util_nodejs-v0.4.17.tar.gz#d31d7d2e1d1534c872dc64e0040d6ce533f11ffb" dependencies: cmake-js "7.2.1" node-addon-api "^6.1.0" From 1766cc081404f2ca15435b89af71bb14bdb1dea5 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 13 Feb 2025 15:23:01 +1100 Subject: [PATCH 2/3] chore: content[14] protobuf already taken. use 15 instead --- protos/SignalService.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protos/SignalService.proto b/protos/SignalService.proto index 7631f2551..8ca4e7c8b 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -42,8 +42,8 @@ message MessageRequestResponse { message Content { - reserved 7, 11; - reserved "configurationMessage", "sharedConfigMessage"; + reserved 7, 11, 14; + reserved "configurationMessage", "sharedConfigMessage", "lastDisappearingMessageChangeTimestamp"; enum ExpirationType { UNKNOWN = 0; @@ -60,7 +60,7 @@ message Content { optional MessageRequestResponse messageRequestResponse = 10; optional ExpirationType expirationType = 12; optional uint32 expirationTimer = 13; - optional uint64 sigTimestamp = 14; + optional uint64 sigTimestamp = 15; } message KeyPair { From 79d3d00646a389bf610a766563670119a824d666 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 13 Feb 2025 16:10:11 +1100 Subject: [PATCH 3/3] fix: address PR comments --- ts/receiver/contentMessage.ts | 4 ++- .../messages/outgoing/ContentMessage.ts | 7 ++-- .../ExpirationTimerUpdateMessage.ts | 8 +++++ .../shouldProcessMessage_test.ts | 34 ++++++++++++------- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index 01e854590..07756f1e5 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -482,7 +482,9 @@ export async function innerHandleSwarmContentMessage({ const content = SignalService.Content.decode(new Uint8Array(contentDecrypted)); if (!shouldProcessContentMessage(envelope, content, false)) { - window.log.info('innerHandleSwarmContentMessage: dropping invalid content message'); + window.log.info( + `innerHandleSwarmContentMessage: dropping invalid content message ${envelope.timestamp}` + ); await IncomingMessageCache.removeFromCache(envelope); return; } diff --git a/ts/session/messages/outgoing/ContentMessage.ts b/ts/session/messages/outgoing/ContentMessage.ts index cf96fabde..07a71cefe 100644 --- a/ts/session/messages/outgoing/ContentMessage.ts +++ b/ts/session/messages/outgoing/ContentMessage.ts @@ -2,11 +2,12 @@ import { SignalService } from '../../../protobuf'; import { TTL_DEFAULT } from '../../constants'; import { Message } from './Message'; -type InstanceKeys = { +type InstanceFields = { // eslint-disable-next-line @typescript-eslint/ban-types [K in keyof T as T[K] extends Function ? never : K]: T[K]; }; -type ContentFields = Partial, 'sigTimestamp'>>; + +type ContentFields = Partial, 'sigTimestamp'>>; export abstract class ContentMessage extends Message { public plainTextBuffer(): Uint8Array { @@ -23,8 +24,8 @@ export abstract class ContentMessage extends Message { public makeContentProto(extra: T) { return new SignalService.Content({ - sigTimestamp: this.createAtNetworkTimestamp, ...extra, + sigTimestamp: this.createAtNetworkTimestamp, }); } diff --git a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts index 48f5e4a0f..77c26bbff 100644 --- a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts @@ -30,6 +30,14 @@ export class ExpirationTimerUpdateMessage extends DataMessage { this.syncTarget = params.syncTarget ? PubKey.cast(params.syncTarget).key : undefined; } + public contentProto(): SignalService.Content { + // TODO: I am pretty sure we don't need this anymore (super.contentProto does the same in DataMessage) + return new SignalService.Content({ + ...super.contentProto(), + dataMessage: this.dataProto(), + }); + } + public dataProto(): SignalService.DataMessage { const data = new SignalService.DataMessage({}); diff --git a/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts b/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts index 4e6557fc8..25106acc0 100644 --- a/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts +++ b/ts/test/session/unit/receiver/drop_incoming/shouldProcessMessage_test.ts @@ -69,39 +69,44 @@ describe('shouldProcessContentMessage', () => { expect( shouldProcessContentMessage( { timestamp: envelopeTs }, - { sigTimestamp: envelopeTs }, // exact match + { sigTimestamp: envelopeTs }, isCommunity - ) + ), + 'exact match' ).to.eq(true); expect( shouldProcessContentMessage( { timestamp: envelopeTs }, - { sigTimestamp: envelopeTs + 6 * DURATION.HOURS - 1 }, // just below 6h of diff (positive) + { sigTimestamp: envelopeTs + 6 * DURATION.HOURS - 1 }, isCommunity - ) + ), + 'just below 6h of diff (positive)' ).to.eq(true); expect( shouldProcessContentMessage( { timestamp: envelopeTs }, - { sigTimestamp: envelopeTs - 6 * DURATION.HOURS + 1 }, // just below 6h of diff (negative) + { sigTimestamp: envelopeTs - 6 * DURATION.HOURS + 1 }, isCommunity - ) + ), + 'just below 6h of diff (negative)' ).to.eq(true); }); it('if timestamps do not roughly match: return false', async () => { expect( shouldProcessContentMessage( { timestamp: envelopeTs }, - { sigTimestamp: envelopeTs + 6 * DURATION.HOURS + 1 }, // just above 6h of diff + { sigTimestamp: envelopeTs + 6 * DURATION.HOURS + 1 }, isCommunity - ) + ), + 'just above 6h of diff' ).to.eq(false); expect( shouldProcessContentMessage( { timestamp: envelopeTs }, - { sigTimestamp: envelopeTs - 6 * DURATION.HOURS - 1 }, // just above 6h of diff + { sigTimestamp: envelopeTs - 6 * DURATION.HOURS - 1 }, isCommunity - ) + ), + 'just above 6h of diff' ).to.eq(false); }); }); @@ -112,17 +117,20 @@ describe('shouldProcessContentMessage', () => { { timestamp: envelopeTs }, { sigTimestamp: undefined as any }, isCommunity - ) + ), + 'sigTimestamp undefined' ).to.eq(true); expect( - shouldProcessContentMessage({ timestamp: envelopeTs }, { sigTimestamp: 0 }, isCommunity) + shouldProcessContentMessage({ timestamp: envelopeTs }, { sigTimestamp: 0 }, isCommunity), + 'sigTimestamp 0 as number' ).to.eq(true); expect( shouldProcessContentMessage( { timestamp: envelopeTs }, { sigTimestamp: Long.fromNumber(0) as any }, isCommunity - ) + ), + 'sigTimestamp 0 as Long' ).to.eq(true); }); });