From 744283fc565ae42d304b1d60cd9a2da0e74df542 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 14 Dec 2023 14:03:41 +1100 Subject: [PATCH] fix: changed some message control to not expire still some to discuss with the team --- .../overlay/OverlayRightPanelSettings.tsx | 3 +-- ts/models/conversation.ts | 15 +++++------ ts/models/message.ts | 6 +++++ ts/receiver/closedGroups.ts | 2 +- ts/receiver/queuedJob.ts | 5 +++- .../apis/snode_api/getExpiriesRequest.ts | 1 - .../conversations/ConversationController.ts | 9 +++++-- ts/session/conversations/createClosedGroup.ts | 24 +++++------------ ts/session/group/closed-group.ts | 26 ++++++++++++++----- .../DataExtractionNotificationMessage.ts | 23 ++++++++++------ .../controlMessage/MessageRequestResponse.ts | 1 + .../outgoing/controlMessage/TypingMessage.ts | 4 +-- 12 files changed, 69 insertions(+), 50 deletions(-) diff --git a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx index e1e09931b..3db8f7c8e 100644 --- a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx +++ b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx @@ -276,8 +276,7 @@ export const OverlayRightPanelSettings = () => { ? window.i18n('youLeftTheGroup') : window.i18n('leaveGroup'); - const showUpdateGroupNameButton = - isGroup && (!isPublic || (isPublic && weAreAdmin)) && !commonNoShow; + const showUpdateGroupNameButton = isGroup && weAreAdmin && !commonNoShow; // legacy groups non-admin cannot change groupname anymore const showAddRemoveModeratorsButton = weAreAdmin && !commonNoShow && isPublic; const showUpdateGroupMembersButton = !isPublic && isGroup && !commonNoShow; diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 186dafac9..c579faebf 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -2038,15 +2038,12 @@ export class ConversationModel extends Backbone.Model { const lastMessageStatus = lastMessageModel.getMessagePropStatus() || undefined; const lastMessageNotificationText = lastMessageModel.getNotificationText() || undefined; // we just want to set the `status` to `undefined` if there are no `lastMessageNotificationText` - const lastMessageUpdate = - !!lastMessageNotificationText && !isEmpty(lastMessageNotificationText) - ? { - lastMessage: lastMessageNotificationText || '', - lastMessageStatus, - } - : { lastMessage: '', lastMessageStatus: undefined }; - - // TODO when the last message get removed from a conversation, the lastUpdate is ignored and we keep the last message. + const lastMessageUpdate = !isEmpty(lastMessageNotificationText) + ? { + lastMessage: lastMessageNotificationText || '', + lastMessageStatus, + } + : { lastMessage: '', lastMessageStatus: undefined }; if ( lastMessageUpdate.lastMessage !== existingLastMessageAttribute || diff --git a/ts/models/message.ts b/ts/models/message.ts index 6784fe598..c6f20b00f 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -486,6 +486,12 @@ export class MessageModel extends Backbone.Model { return undefined; } + // some incoming legacy group updates are outgoing, but when synced to our other devices have just the received_at field set. + // when that is the case, we don't want to render the spinning 'sending' state + if (this.get('received_at')) { + return undefined; + } + if (this.isDataExtractionNotification() || this.get('callNotificationType')) { return undefined; } diff --git a/ts/receiver/closedGroups.ts b/ts/receiver/closedGroups.ts index fc003c632..1b7217d20 100644 --- a/ts/receiver/closedGroups.ts +++ b/ts/receiver/closedGroups.ts @@ -946,7 +946,7 @@ async function sendLatestKeyPairToUsers( groupId: groupPubKey, timestamp: Date.now(), encryptedKeyPairs: wrappers, - expirationType: null, + expirationType: null, // we keep that one **not** expiring (not rendered in the clients, and we need it to be as available as possible on the swarm) expireTimer: null, }); diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts index 6de1e12d0..a217d0a7a 100644 --- a/ts/receiver/queuedJob.ts +++ b/ts/receiver/queuedJob.ts @@ -360,7 +360,10 @@ export async function handleMessageJob( window?.log?.info( `Starting handleMessageJob for message ${messageModel.idForLogging()}, ${messageModel.get( 'serverTimestamp' - ) || messageModel.get('timestamp')} in conversation ${conversation.idForLogging()}` + ) || + messageModel.get( + 'timestamp' + )} in conversation ${conversation.idForLogging()}, messageHash:${messageHash}` ); const sendingDeviceConversation = await getConversationController().getOrCreateAndWait( diff --git a/ts/session/apis/snode_api/getExpiriesRequest.ts b/ts/session/apis/snode_api/getExpiriesRequest.ts index 13e7a3bcd..f3012ab8b 100644 --- a/ts/session/apis/snode_api/getExpiriesRequest.ts +++ b/ts/session/apis/snode_api/getExpiriesRequest.ts @@ -70,7 +70,6 @@ async function getExpiriesFromNodes( throw Error(`getExpiriesFromNodes result is not 200 but ${firstResult.code}`); } - debugger; // expirationResults is a record of {messageHash: currentExpiry} const expirationResults = await processGetExpiriesRequestResponse( targetNode, diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts index 4b08b907e..a0abf2e0a 100644 --- a/ts/session/conversations/ConversationController.ts +++ b/ts/session/conversations/ConversationController.ts @@ -26,6 +26,7 @@ import { OpenGroupUtils } from '../apis/open_group_api/utils'; import { getSwarmPollingInstance } from '../apis/snode_api'; import { GetNetworkTime } from '../apis/snode_api/getNetworkTime'; import { SnodeNamespaces } from '../apis/snode_api/namespaces'; +import { DisappearingMessages } from '../disappearing_messages'; import { ClosedGroupMemberLeftMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupMemberLeftMessage'; import { UserUtils } from '../utils'; import { ConfigurationSync } from '../utils/job_runners/jobs/ConfigurationSyncJob'; @@ -496,8 +497,12 @@ async function leaveClosedGroup(groupId: string, fromSyncMessage: boolean) { const ourLeavingMessage = new ClosedGroupMemberLeftMessage({ timestamp: networkTimestamp, groupId, - expirationType: null, - expireTimer: null, + expirationType: DisappearingMessages.changeToDisappearingMessageType( + convo, + convo.getExpireTimer(), + convo.getExpirationMode() + ), + expireTimer: convo.getExpireTimer(), }); window?.log?.info(`We are leaving the group ${groupId}. Sending our leaving message.`); diff --git a/ts/session/conversations/createClosedGroup.ts b/ts/session/conversations/createClosedGroup.ts index bb4601dba..ca569b7ea 100644 --- a/ts/session/conversations/createClosedGroup.ts +++ b/ts/session/conversations/createClosedGroup.ts @@ -8,7 +8,6 @@ import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { getSwarmPollingInstance } from '../apis/snode_api'; import { SnodeNamespaces } from '../apis/snode_api/namespaces'; import { generateClosedGroupPublicKey, generateCurve25519KeyPairWithoutPrefix } from '../crypto'; -import { DisappearAfterSendOnly, DisappearingMessageType } from '../disappearing_messages/types'; import { ClosedGroupNewMessage, ClosedGroupNewMessageParams, @@ -68,15 +67,14 @@ export async function createClosedGroup(groupName: string, members: Array, encryptionKeyPair: ECKeyPair, - existingExpirationType: DisappearAfterSendOnly, - existingExpireTimer: number, isRetry: boolean = false ): Promise { const promises = createInvitePromises( @@ -112,9 +108,7 @@ async function sendToGroupMembers( groupPublicKey, groupName, admins, - encryptionKeyPair, - existingExpirationType, - existingExpireTimer + encryptionKeyPair ); window?.log?.info(`Sending invites for group ${groupPublicKey} to ${listOfMembers}`); // evaluating if all invites sent, if failed give the option to retry failed invites via modal dialog @@ -169,8 +163,6 @@ async function sendToGroupMembers( groupName, admins, encryptionKeyPair, - existingExpirationType, - existingExpireTimer, isRetrySend ); } @@ -186,9 +178,7 @@ function createInvitePromises( groupPublicKey: string, groupName: string, admins: Array, - encryptionKeyPair: ECKeyPair, - existingExpirationType: DisappearingMessageType, - existingExpireTimer: number + encryptionKeyPair: ECKeyPair ) { return listOfMembers.map(async m => { const messageParams: ClosedGroupNewMessageParams = { @@ -198,8 +188,8 @@ function createInvitePromises( admins, keypair: encryptionKeyPair, timestamp: Date.now(), - expirationType: existingExpirationType, - expireTimer: existingExpireTimer, + expirationType: null, // Note: we do not make those messages expire as we want them available as much as possible on the swarm of the recipient + expireTimer: 0, }; const message = new ClosedGroupNewMessage(messageParams); return getMessageQueue().sendToPubKeyNonDurably({ diff --git a/ts/session/group/closed-group.ts b/ts/session/group/closed-group.ts index 3c74a9794..13efce4d1 100644 --- a/ts/session/group/closed-group.ts +++ b/ts/session/group/closed-group.ts @@ -290,8 +290,12 @@ async function sendNewName(convo: ConversationModel, name: string, messageId: st groupId, identifier: messageId, name, - expirationType: null, - expireTimer: null, + expirationType: DisappearingMessages.changeToDisappearingMessageType( + convo, + convo.getExpireTimer(), + convo.getExpirationMode() + ), + expireTimer: convo.getExpireTimer(), }); await getMessageQueue().sendToGroup({ message: nameChangeMessage, @@ -328,8 +332,12 @@ async function sendAddedMembers( groupId, addedMembers, identifier: messageId, - expirationType: null, - expireTimer: null, + expirationType: DisappearingMessages.changeToDisappearingMessageType( + convo, + convo.getExpireTimer(), + convo.getExpirationMode() + ), + expireTimer: convo.getExpireTimer(), }); await getMessageQueue().sendToGroup({ message: closedGroupControlMessage, @@ -393,8 +401,12 @@ export async function sendRemovedMembers( groupId, removedMembers, identifier: messageId, - expirationType: null, - expireTimer: null, + expirationType: DisappearingMessages.changeToDisappearingMessageType( + convo, + convo.getExpireTimer(), + convo.getExpirationMode() + ), + expireTimer: convo.getExpireTimer(), }); // Send the group update, and only once sent, generate and distribute a new encryption key pair if needed await getMessageQueue().sendToGroup({ @@ -455,7 +467,7 @@ async function generateAndSendNewEncryptionKeyPair( groupId: toHex(groupId), timestamp: GetNetworkTime.getNowWithNetworkOffset(), encryptedKeyPairs: wrappers, - expirationType: null, + expirationType: null, // we keep that one **not** expiring (not rendered in the clients, and we need it to be as available as possible on the swarm) expireTimer: null, }); diff --git a/ts/session/messages/outgoing/controlMessage/DataExtractionNotificationMessage.ts b/ts/session/messages/outgoing/controlMessage/DataExtractionNotificationMessage.ts index a0e785433..945e85a52 100644 --- a/ts/session/messages/outgoing/controlMessage/DataExtractionNotificationMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/DataExtractionNotificationMessage.ts @@ -1,23 +1,21 @@ -import { v4 as uuid } from 'uuid'; - -import { ContentMessage } from '..'; import { getMessageQueue } from '../../..'; import { SignalService } from '../../../../protobuf'; import { SnodeNamespaces } from '../../../apis/snode_api/namespaces'; import { getConversationController } from '../../../conversations'; +import { DisappearingMessages } from '../../../disappearing_messages'; import { PubKey } from '../../../types'; import { UserUtils } from '../../../utils'; -import { MessageParams } from '../Message'; +import { ExpirableMessage, ExpirableMessageParams } from '../ExpirableMessage'; -interface DataExtractionNotificationMessageParams extends MessageParams { +interface DataExtractionNotificationMessageParams extends ExpirableMessageParams { referencedAttachmentTimestamp: number; } -export class DataExtractionNotificationMessage extends ContentMessage { +export class DataExtractionNotificationMessage extends ExpirableMessage { public readonly referencedAttachmentTimestamp: number; constructor(params: DataExtractionNotificationMessageParams) { - super({ timestamp: params.timestamp, identifier: params.identifier }); + super(params); this.referencedAttachmentTimestamp = params.referencedAttachmentTimestamp; // this does not make any sense if (!this.referencedAttachmentTimestamp) { @@ -57,11 +55,20 @@ export const sendDataExtractionNotification = async ( return; } + const expireTimer = convo.getExpireTimer(); + const expirationType = DisappearingMessages.changeToDisappearingMessageType( + convo, + expireTimer, + convo.getExpirationMode() + ); + const dataExtractionNotificationMessage = new DataExtractionNotificationMessage({ referencedAttachmentTimestamp, - identifier: uuid(), timestamp: Date.now(), + expirationType, + expireTimer, }); + const pubkey = PubKey.cast(conversationId); window.log.info( `Sending DataExtractionNotification to ${conversationId} about attachment: ${referencedAttachmentTimestamp}` diff --git a/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts b/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts index 0bc5af5ca..547b4afb7 100644 --- a/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts +++ b/ts/session/messages/outgoing/controlMessage/MessageRequestResponse.ts @@ -4,6 +4,7 @@ import { ContentMessage } from '../ContentMessage'; import { MessageParams } from '../Message'; import { buildProfileForOutgoingMessage } from '../visibleMessage/VisibleMessage'; +// Note: a MessageRequestResponse message should not expire at all on the recipient side/nor our side. export interface MessageRequestResponseParams extends MessageParams { lokiProfile?: LokiProfile; } diff --git a/ts/session/messages/outgoing/controlMessage/TypingMessage.ts b/ts/session/messages/outgoing/controlMessage/TypingMessage.ts index 719f72963..b5e7ee39f 100644 --- a/ts/session/messages/outgoing/controlMessage/TypingMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/TypingMessage.ts @@ -1,7 +1,7 @@ +import { ContentMessage } from '..'; +import { Constants } from '../../..'; import { SignalService } from '../../../../protobuf'; import { MessageParams } from '../Message'; -import { Constants } from '../../..'; -import { ContentMessage } from '..'; interface TypingMessageParams extends MessageParams { isTyping: boolean;