diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index a8427bafe..a771ea0a5 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -740,7 +740,11 @@ export class ConversationModel extends Backbone.Model { const { attachments, body, groupInvitation, preview, quote } = msg; this.clearTypingTimers(); const expireTimer = this.get('expireTimer'); - const expirationType = changeToDisappearingMessageType(this, this.get('expirationType')); + const expirationType = changeToDisappearingMessageType( + this, + expireTimer, + this.get('expirationType') + ); const networkTimestamp = GetNetworkTime.getNowWithNetworkOffset(); @@ -882,7 +886,11 @@ export class ConversationModel extends Backbone.Model { }); let message: MessageModel | undefined = existingMessage || undefined; - const messageExpirationType = changeToDisappearingMessageType(this, expirationType); + const messageExpirationType = changeToDisappearingMessageType( + this, + expireTimer, + expirationType + ); window.log.debug(`WIP: updateExpireTimer() messageExpirationType: ${messageExpirationType}`); // we don't have info about who made the change and when, when we get a change from a config message, so do not add a control message @@ -897,7 +905,6 @@ export class ConversationModel extends Backbone.Model { source, fromSync, }, - // TODO Confirm that legacy devices ignore this and that everything works expirationType: messageExpirationType, expireTimer, }; diff --git a/ts/receiver/closedGroups.ts b/ts/receiver/closedGroups.ts index ae369eca7..63a2efcf6 100644 --- a/ts/receiver/closedGroups.ts +++ b/ts/receiver/closedGroups.ts @@ -84,7 +84,7 @@ export async function handleClosedGroupControlMessage( const { type } = groupUpdate; const { Type } = SignalService.DataMessage.ClosedGroupControlMessage; window?.log?.info( - ` handle closed group update from ${envelope.senderIdentity || envelope.source} about group ${ + `handle closed group update from ${envelope.senderIdentity || envelope.source} about group ${ envelope.source }` ); diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index 12e7cd75f..64e9d3cf1 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -469,8 +469,8 @@ export async function innerHandleSwarmContentMessage( window.log.debug(`WIP: innerHandleSwarmContentMessage: ${JSON.stringify(content)}`); const expireUpdate = await checkForExpireUpdateInContentMessage( - conversationModelForUIUpdate, - content + content, + conversationModelForUIUpdate ); window.log.debug( @@ -478,7 +478,7 @@ export async function innerHandleSwarmContentMessage( ); // TODO legacy messages support will be removed in a future release - if (expireUpdate && !isEmpty(expireUpdate) && expireUpdate.isDisappearingMessagesV2Released) { + if (expireUpdate.isDisappearingMessagesV2Released) { await checkHasOutdatedClient( conversationModelForUIUpdate, senderConversationModel, @@ -486,7 +486,7 @@ export async function innerHandleSwarmContentMessage( ); if (expireUpdate.isLegacyConversationSettingMessage) { window.log.debug( - 'The legacy message is an expiration timer update. Ignoring it.', + 'WIP: The legacy message is an expiration timer update. Ignoring it.', content ); return; @@ -861,7 +861,7 @@ export async function handleDataExtractionNotification( if (convo && expirationMode && expireTimer > 0) { expirationType = expirationType !== 'off' - ? changeToDisappearingMessageType(convo, expirationMode) + ? changeToDisappearingMessageType(convo, expireTimer, expirationMode) : undefined; if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') { diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts index c83332162..167599d70 100644 --- a/ts/receiver/dataMessage.ts +++ b/ts/receiver/dataMessage.ts @@ -25,7 +25,7 @@ import { isUsFromCache } from '../session/utils/User'; import { Action, Reaction } from '../types/Reaction'; import { toLogFormat } from '../types/attachments/Errors'; import { Reactions } from '../util/reactions'; -import { DisappearingMessageUpdate, handleExpireUpdate } from '../util/expiringMessages'; +import { DisappearingMessageUpdate, updateMessageModelToExpire } from '../util/expiringMessages'; function cleanAttachment(attachment: any) { return { @@ -159,7 +159,7 @@ export async function handleSwarmDataMessage( rawDataMessage: SignalService.DataMessage, messageHash: string, senderConversationModel: ConversationModel, - expireUpdate?: DisappearingMessageUpdate + expireUpdate: DisappearingMessageUpdate ): Promise { window.log.info('handleSwarmDataMessage'); @@ -261,10 +261,8 @@ export async function handleSwarmDataMessage( sentAt: sentAtTimestamp, }); - if (!isEmpty(expireUpdate)) { - msgModel = handleExpireUpdate(convoToAddMessageTo, msgModel, expireUpdate); - window.log.debug(`WIP: innerHandleSwarmContentMessage msgModel ${JSON.stringify(msgModel)}`); - } + msgModel = updateMessageModelToExpire(convoToAddMessageTo, msgModel, expireUpdate); + window.log.debug(`WIP: innerHandleSwarmContentMessage msgModel ${JSON.stringify(msgModel)}`); await handleSwarmMessage( msgModel, diff --git a/ts/session/group/closed-group.ts b/ts/session/group/closed-group.ts index b818c73f1..4eacd0120 100644 --- a/ts/session/group/closed-group.ts +++ b/ts/session/group/closed-group.ts @@ -72,7 +72,11 @@ export async function initiateClosedGroupUpdate( isGroupV3 ? ConversationTypeEnum.GROUPV3 : ConversationTypeEnum.GROUP ); - const expirationType = changeToDisappearingMessageType(convo, convo.get('expirationType')); + const expirationType = changeToDisappearingMessageType( + convo, + convo.get('expireTimer'), + convo.get('expirationType') + ); if (expirationType === 'deleteAfterRead') { throw new Error(`Groups cannot be deleteAfterRead. convo id: ${convo.id}`); @@ -176,7 +180,9 @@ export async function addUpdateMessage( if (convo && expirationMode && expireTimer > 0) { expirationType = - expirationMode !== 'off' ? changeToDisappearingMessageType(convo, expirationMode) : undefined; + expirationMode !== 'off' + ? changeToDisappearingMessageType(convo, convo.get('expireTimer'), expirationMode) + : undefined; if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') { expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, sentAt); @@ -327,7 +333,7 @@ async function sendAddedMembers( members, keypair: encryptionKeyPair, identifier: messageId || uuidv4(), - expirationType: changeToDisappearingMessageType(convo, expirationMode), + expirationType: changeToDisappearingMessageType(convo, existingExpireTimer, expirationMode), expireTimer: existingExpireTimer, }); diff --git a/ts/session/utils/calling/CallManager.ts b/ts/session/utils/calling/CallManager.ts index 730555ef6..e5d26f721 100644 --- a/ts/session/utils/calling/CallManager.ts +++ b/ts/session/utils/calling/CallManager.ts @@ -522,7 +522,7 @@ export async function USER_callRecipient(recipient: string) { let expirationStartTimestamp; if (calledConvo && expirationMode && expireTimer > 0) { - expirationType = changeToDisappearingMessageType(calledConvo, expirationMode); + expirationType = changeToDisappearingMessageType(calledConvo, expireTimer, expirationMode); if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') { expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, now); @@ -902,7 +902,7 @@ export async function USER_acceptIncomingCallRequest(fromSender: string) { let expirationStartTimestamp; if (callerConvo && expirationMode && expireTimer > 0) { - expirationType = changeToDisappearingMessageType(callerConvo, expirationMode); + expirationType = changeToDisappearingMessageType(callerConvo, expireTimer, expirationMode); if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') { expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, networkTimestamp); @@ -1254,7 +1254,11 @@ async function addMissedCallMessage(callerPubkey: string, sentAt: number) { let expirationStartTimestamp; if (incomingCallConversation && expirationMode && expireTimer > 0) { - expirationType = changeToDisappearingMessageType(incomingCallConversation, expirationMode); + expirationType = changeToDisappearingMessageType( + incomingCallConversation, + expireTimer, + expirationMode + ); if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') { expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, sentAt); diff --git a/ts/util/expiringMessages.ts b/ts/util/expiringMessages.ts index e83f35ed3..9686a542e 100644 --- a/ts/util/expiringMessages.ts +++ b/ts/util/expiringMessages.ts @@ -310,6 +310,7 @@ export function isLegacyDisappearingModeEnabled( */ export function changeToDisappearingMessageType( convo: ConversationModel, + expireTimer: number, expirationType?: DisappearingMessageConversationType ): DisappearingMessageType { if (expirationType === 'off' || expirationType === 'legacy') { @@ -317,10 +318,14 @@ export function changeToDisappearingMessageType( return 'unknown'; } - if (convo.isMe() || convo.isClosedGroup()) { - return 'deleteAfterSend'; + if (expireTimer > 0) { + if (convo.isMe() || convo.isClosedGroup()) { + return 'deleteAfterSend'; + } + return 'deleteAfterRead'; } - return 'deleteAfterRead'; + + return 'unknown'; } // TODO legacy messages support will be removed in a future release @@ -368,9 +373,9 @@ function checkIsLegacyDisappearingDataMessage(dataMessage: SignalService.DataMes // TODO legacy messages support will be removed in a future release export async function checkForExpireUpdateInContentMessage( - convoToUpdate: ConversationModel, - content: SignalService.Content -): Promise { + content: SignalService.Content, + convoToUpdate: ConversationModel +): Promise { const dataMessage = content.dataMessage as SignalService.DataMessage; // We will only support legacy disappearing messages for a short period before disappearing messages v2 is unlocked const isDisappearingMessagesV2Released = await ReleasedFeatures.checkIsDisappearMessageV2FeatureReleased(); @@ -382,17 +387,16 @@ export async function checkForExpireUpdateInContentMessage( ); const isLegacyConversationSettingMessage = isDisappearingMessagesV2Released ? isLegacyContentMessage && - isLegacyDataMessage && + (isLegacyDataMessage || !content.lastDisappearingMessageChangeTimestamp) && dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE : isLegacyContentMessage && dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; - let expirationTimer = isLegacyDataMessage + const expirationTimer = isLegacyDataMessage ? Number(dataMessage.expireTimer) : content.expirationTimer; - // NOTE This starts are a DisappearingMessageConversationType but we will convert it to a DisappearingMessageType for the final return - let expirationMode: any = changeToDisappearingMessageConversationType( + const expirationMode = changeToDisappearingMessageConversationType( convoToUpdate, DisappearingMessageMode[content.expirationType], expirationTimer @@ -402,13 +406,14 @@ export async function checkForExpireUpdateInContentMessage( ? Number(content.lastDisappearingMessageChangeTimestamp) : undefined; - // TODO should review this - const shouldDisappearButIsntMessage = - dataMessage.flags !== SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE && - expirationMode === 'off' && - expirationTimer === 0 && - convoToUpdate.get('expirationType') !== 'off' && - convoToUpdate.get('expireTimer') !== 0; + const expireUpdate: DisappearingMessageUpdate = { + expirationType: changeToDisappearingMessageType(convoToUpdate, expirationTimer, expirationMode), + expirationTimer, + lastDisappearingMessageChangeTimestamp, + isLegacyConversationSettingMessage, + isLegacyDataMessage, + isDisappearingMessagesV2Released, + }; // NOTE some platforms do not include the diappearing message values in the Data Message for sent messages so we have to trust the conversation settings until v2 is released if ( @@ -426,15 +431,27 @@ export async function checkForExpireUpdateInContentMessage( content, convoToUpdate ); - expirationTimer = convoToUpdate.get('expireTimer'); - expirationMode = changeToDisappearingMessageType( + + expireUpdate.expirationTimer = convoToUpdate.get('expireTimer'); + expireUpdate.expirationType = changeToDisappearingMessageType( convoToUpdate, + expireUpdate.expirationTimer, convoToUpdate.get('expirationType') ); + expireUpdate.isLegacyDataMessage = true; } } - // NOTE If it is a legacy message and disappearing messages v2 is released then we ignore it and use the local client's conversation settings + // TODO should review this + // NOTE this is only required for legacy disappearing message conversation settings I think? + const shouldDisappearButIsntMessage = + dataMessage.flags !== SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE && + expirationMode === 'off' && + expirationTimer === 0 && + convoToUpdate.get('expirationType') !== 'off' && + convoToUpdate.get('expireTimer') !== 0; + + // NOTE If it is a legacy message and disappearing messages v2 is released then we ignore it and use the local client's conversation settings andshow the outdated client banner if ( isDisappearingMessagesV2Released && (isLegacyDataMessage || isLegacyConversationSettingMessage || shouldDisappearButIsntMessage) @@ -443,24 +460,21 @@ export async function checkForExpireUpdateInContentMessage( 'WIP: Received a legacy disappearing message after v2 was released. Overriding it with the conversation settings', content ); - expirationTimer = convoToUpdate.get('expireTimer'); - expirationMode = convoToUpdate.get('expirationType'); - } - const expireUpdate: DisappearingMessageUpdate = { - expirationType: changeToDisappearingMessageType(convoToUpdate, expirationMode), - expirationTimer, - lastDisappearingMessageChangeTimestamp, - isLegacyConversationSettingMessage, - isLegacyDataMessage, - isDisappearingMessagesV2Released, - }; + expireUpdate.expirationTimer = convoToUpdate.get('expireTimer'); + expireUpdate.expirationType = changeToDisappearingMessageType( + convoToUpdate, + expireUpdate.expirationTimer, + convoToUpdate.get('expirationType') + ); + expireUpdate.isLegacyDataMessage = true; + } return expireUpdate; } // TODO legacy messages support will be removed in a future release -export function handleExpireUpdate( +export function updateMessageModelToExpire( converationModel: ConversationModel, messageModel: MessageModel, expireUpdate?: DisappearingMessageUpdate @@ -470,7 +484,9 @@ export function handleExpireUpdate( } if (converationModel.isPublic()) { - window.log.warn("updateExpireTimer() Disappearing messages aren't supported in communities"); + window.log.warn( + "updateMessageModelToExpire() Disappearing messages aren't supported in communities" + ); return messageModel; } @@ -514,12 +530,14 @@ export async function checkHasOutdatedClient( sender: ConversationModel, expireUpdate: DisappearingMessageUpdate ) { + const isOutdated = + expireUpdate.isLegacyDataMessage || expireUpdate.isLegacyConversationSettingMessage; const outdatedSender = sender.get('nickname') || sender.get('displayNameInProfile') || sender.get('id'); if (convoToUpdate.get('hasOutdatedClient')) { // trigger notice banner - if (expireUpdate.isLegacyDataMessage || expireUpdate.isLegacyConversationSettingMessage) { + if (isOutdated) { if (convoToUpdate.get('hasOutdatedClient') !== outdatedSender) { convoToUpdate.set({ hasOutdatedClient: outdatedSender, @@ -534,7 +552,7 @@ export async function checkHasOutdatedClient( return; } - if (expireUpdate.isLegacyDataMessage || expireUpdate.isLegacyConversationSettingMessage) { + if (isOutdated) { convoToUpdate.set({ hasOutdatedClient: outdatedSender, });