From d698f66d50b27e511e32de1a7408a2fbcefd6dd7 Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 3 Apr 2023 14:09:05 +0200 Subject: [PATCH] feat: updated clients can send ExpirationTimerUpdateMessages to older clients fixed syncing of ExpirationTimerUpdateMessages --- ts/models/conversation.ts | 6 +- ts/models/message.ts | 63 ++++++++++--------- ts/models/messageType.ts | 6 +- .../ExpirationTimerUpdateMessage.ts | 17 +++-- ts/session/sending/MessageSentHandler.ts | 10 +-- ts/session/utils/syncUtils.ts | 8 ++- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 40e322d19..faf5bd3f7 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -1,7 +1,6 @@ import Backbone from 'backbone'; import { debounce, - defaults, filter, includes, isArray, @@ -1058,7 +1057,7 @@ export class ConversationModel extends Backbone.Model { providedChangeTimestamp, providedSource, receivedAt, // is set if it comes from outside - fromSync, + fromSync = false, shouldCommit = true, existingMessage, }: { @@ -1076,8 +1075,6 @@ export class ConversationModel extends Backbone.Model { const lastDisappearingMessageChangeTimestamp = providedChangeTimestamp; let source = providedSource; - defaults({ fromSync }, { fromSync: false }); - if (!expirationType || !expireTimer) { expirationType = 'off'; expireTimer = 0; @@ -1191,7 +1188,6 @@ export class ConversationModel extends Backbone.Model { } if (this.isPrivate()) { - // TODO Check that the args are correct const expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdate); const pubkey = new PubKey(this.get('id')); await getMessageQueue().sendToPubKey(pubkey, expirationTimerMessage); diff --git a/ts/models/message.ts b/ts/models/message.ts index 731d93963..e9618d009 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -4,7 +4,7 @@ import filesize from 'filesize'; import { SignalService } from '../../ts/protobuf'; import { getMessageQueue } from '../../ts/session'; import { getConversationController } from '../../ts/session/conversations'; -import { DataMessage } from '../../ts/session/messages/outgoing'; +import { ContentMessage } from '../../ts/session/messages/outgoing'; import { ClosedGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage'; import { PubKey } from '../../ts/session/types'; import { @@ -82,6 +82,7 @@ import { loadQuoteData, } from '../types/MessageAttachment'; import { + DisappearingMessageConversationSetting, DisappearingMessageUpdate, ExpirationTimerOptions, setExpirationStartTimestamp, @@ -1063,8 +1064,7 @@ export class MessageModel extends Backbone.Model { await this.commit(); } - public async sendSyncMessageOnly(dataMessage: DataMessage) { - const contentMessage = dataMessage.contentProto(); + public async sendSyncMessageOnly(contentMessage: ContentMessage) { const now = Date.now(); this.set({ @@ -1072,51 +1072,56 @@ export class MessageModel extends Backbone.Model { sent: true, }); - let expireUpdate: DisappearingMessageUpdate | null = null; - const expirationType = dataMessage.getDisappearingMessageType(); - - if (expirationType && contentMessage.expirationTimer) { - expireUpdate = { - expirationType, - expireTimer: contentMessage.expirationTimer, - lastDisappearingMessageChangeTimestamp: Number( - contentMessage.lastDisappearingMessageChangeTimestamp - ), - }; - } - await this.commit(); - await this.sendSyncMessage(dataMessage, now, expireUpdate || undefined); + const content = + contentMessage instanceof ContentMessage ? contentMessage.contentProto() : contentMessage; + await this.sendSyncMessage(content, now); } - public async sendSyncMessage( - data: DataMessage | SignalService.DataMessage, - sentTimestamp: number, - expireUpdate?: DisappearingMessageUpdate - ) { + public async sendSyncMessage(content: SignalService.Content, sentTimestamp: number) { if (this.get('synced') || this.get('sentSync')) { return; } + const { dataMessage } = content; - const dataMessage = data instanceof DataMessage ? data.dataProto() : data; - + // TODO maybe we need to account for lastDisappearingMessageChangeTimestamp? // if this message needs to be synced if ( - dataMessage.body?.length || - dataMessage.attachments.length || - dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE + dataMessage && + (dataMessage.body?.length || + dataMessage.attachments?.length || + dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE) ) { const conversation = this.getConversation(); if (!conversation) { throw new Error('Cannot trigger syncMessage with unknown convo.'); } + + // TODO legacy messages support will be removed in a future release + const expirationType = content.expirationType + ? DisappearingMessageConversationSetting[content.expirationType] + : DisappearingMessageConversationSetting[3]; + const expireTimer = content.expirationTimer || content?.dataMessage?.expireTimer || undefined; + const lastDisappearingMessageChangeTimestamp = content.lastDisappearingMessageChangeTimestamp + ? Number(content.lastDisappearingMessageChangeTimestamp) + : undefined; + let expireUpdate: DisappearingMessageUpdate | null = null; + + if (expirationType && expireTimer !== undefined) { + expireUpdate = { + expirationType, + expireTimer, + lastDisappearingMessageChangeTimestamp, + }; + } + const syncMessage = buildSyncMessage( this.id, - data, + dataMessage as SignalService.DataMessage, conversation.id, sentTimestamp, - expireUpdate + expireUpdate || undefined ); await getMessageQueue().sendSyncMessage(syncMessage); } diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts index bf0ff3d2e..67f4c86fa 100644 --- a/ts/models/messageType.ts +++ b/ts/models/messageType.ts @@ -180,10 +180,12 @@ export interface MessageAttributesOptionals { expireTimer?: number; expirationStartTimestamp?: number; expires_at?: number; + // TODO legacy messages support will be removed in a future release + // types will no longer have an undefined option expirationTimerUpdate?: { - expirationType: DisappearingMessageType; + expirationType: DisappearingMessageType | undefined; expireTimer: number; - lastDisappearingMessageChangeTimestamp: number; + lastDisappearingMessageChangeTimestamp: number | undefined; source: string; fromSync?: boolean; }; diff --git a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts index ddcf3d3ab..06fa6c5ab 100644 --- a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts @@ -7,17 +7,16 @@ import { ExpirableMessageParams } from '../ExpirableMessage'; interface ExpirationTimerUpdateMessageParams extends ExpirableMessageParams { groupId?: string | PubKey; syncTarget?: string | PubKey; - lastDisappearingMessageChangeTimestamp: number | null; + lastDisappearingMessageChangeTimestamp?: number; } -// Note the old disappearing messages used a data message for the expiration time. +// NOTE legacy messages used a data message for the expireTimer. // The new ones use properties on the Content Message -// We will remove support for the old one 2 weeks after the release + export class ExpirationTimerUpdateMessage extends DataMessage { public readonly groupId?: PubKey; public readonly syncTarget?: string; - // TODO should this typing be updated - public readonly lastDisappearingMessageChangeTimestamp: number | null; + public readonly lastDisappearingMessageChangeTimestamp?: number; constructor(params: ExpirationTimerUpdateMessageParams) { super({ @@ -64,10 +63,10 @@ export class ExpirationTimerUpdateMessage extends DataMessage { data.syncTarget = this.syncTarget; } - // TODO should only happen in legacy mode and should be cancelled out once we have trigger the unix timestamp - // if (this.expireTimer) { - // data.expireTimer = this.expireTimer; - // } + // TODO legacy messages support will be removed in a future release + if (this.expirationType === 'legacy' && this.expireTimer) { + data.expireTimer = this.expireTimer; + } return data; } diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index 5f61b4e89..9b95178ad 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -70,9 +70,7 @@ async function handleMessageSentSuccess( !isOurDevice && !isClosedGroupMessage && !fetchedMessage.get('synced') && - !fetchedMessage.get('sentSync') && - // TODO not 100% on this. Handling syncing later - !fetchedMessage.get('expirationType'); + !fetchedMessage.get('sentSync'); // A message is synced if we triggered a sync message (sentSync) // and the current message was sent to our device (so a sync message) @@ -105,10 +103,7 @@ async function handleMessageSentSuccess( if (shouldTriggerSyncMessage) { if (dataMessage) { try { - await fetchedMessage.sendSyncMessage( - dataMessage as SignalService.DataMessage, - effectiveTimestamp - ); + await fetchedMessage.sendSyncMessage(contentDecoded, effectiveTimestamp); const tempFetchMessage = await fetchHandleMessageSentData(sentMessage.identifier); if (!tempFetchMessage) { window?.log?.warn( @@ -123,7 +118,6 @@ async function handleMessageSentSuccess( } } else if (shouldMarkMessageAsSynced) { fetchedMessage.set({ synced: true }); - // TODO handle sync messages separately } sentTo = _.union(sentTo, [sentMessage.device]); diff --git a/ts/session/utils/syncUtils.ts b/ts/session/utils/syncUtils.ts index f4e02fd39..002195f21 100644 --- a/ts/session/utils/syncUtils.ts +++ b/ts/session/utils/syncUtils.ts @@ -307,7 +307,7 @@ const buildSyncExpireTimerMessage = ( timestamp, expirationType, expireTimer, - lastDisappearingMessageChangeTimestamp: lastDisappearingMessageChangeTimestamp || null, + lastDisappearingMessageChangeTimestamp, syncTarget, }); }; @@ -347,7 +347,11 @@ export const buildSyncMessage = ( ) { return buildSyncExpireTimerMessage(identifier, expireUpdate, timestamp, syncTarget); } else { - window.log.info(`WIP: Something went wrong when syncing a disappearing message`); + window.log.info( + `WIP: Something went wrong when syncing a disappearing message`, + dataMessage, + expireUpdate + ); } return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget); };