diff --git a/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx b/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx index 6eaac91b9..d444a2509 100644 --- a/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx +++ b/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx @@ -64,8 +64,9 @@ function useIsExpired(props: PropsForExpiringMessage) { return { isExpired }; } -const StyledReadableMessage = styled(ReadableMessage)` +const StyledReadableMessage = styled(ReadableMessage)<{ isIncoming: boolean }>` display: flex; + justify-content: ${props => (props.isIncoming ? 'flex-start' : 'flex-end')}; align-items: center; width: 100%; `; @@ -106,6 +107,7 @@ export const ExpirableReadableMessage = (props: ExpirableReadableMessageProps) = messageId={messageId} receivedAt={receivedAt} isUnread={!!isUnread} + isIncoming={isIncoming} key={`readable-message-${messageId}`} > {expirationLength && expirationTimestamp && ( diff --git a/ts/components/conversation/message/message-item/GroupInvitation.tsx b/ts/components/conversation/message/message-item/GroupInvitation.tsx index ca11c53fd..ec41848a5 100644 --- a/ts/components/conversation/message/message-item/GroupInvitation.tsx +++ b/ts/components/conversation/message/message-item/GroupInvitation.tsx @@ -3,8 +3,8 @@ import classNames from 'classnames'; import { PropsForGroupInvitation } from '../../../../state/ducks/conversations'; import { acceptOpenGroupInvitation } from '../../../../interactions/messageInteractions'; import { SessionIconButton } from '../../../icon'; -import { ReadableMessage } from './ReadableMessage'; import styled from 'styled-components'; +import { ExpirableReadableMessage } from './ExpirableReadableMessage'; const StyledIconContainer = styled.div` background-color: var(--message-link-preview-background-color); @@ -21,10 +21,15 @@ export const GroupInvitation = (props: PropsForGroupInvitation) => { const openGroupInvitation = window.i18n('openGroupInvitation'); return ( -
@@ -52,6 +57,6 @@ export const GroupInvitation = (props: PropsForGroupInvitation) => {
-
+ ); }; diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index b12c4994f..fa2822e99 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -636,7 +636,8 @@ export class ConversationModel extends Backbone.Model { timestamp: sentAt, name: groupInvitation.name, url: groupInvitation.url, - expireTimer: this.get('expireTimer'), + expirationType, + expireTimer, }); // we need the return await so that errors are caught in the catch {} await getMessageQueue().sendToPubKey(destinationPubkey, groupInviteMessage); diff --git a/ts/models/message.ts b/ts/models/message.ts index 642b9d772..a50622b45 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -35,6 +35,7 @@ import { messagesChanged, PropsForAttachment, PropsForExpirationTimer, + PropsForExpiringMessage, PropsForGroupInvitation, PropsForGroupUpdate, PropsForGroupUpdateAdd, @@ -91,7 +92,7 @@ import { getUsBlindedInThatServer, isUsAnySogsFromCache, } from '../session/apis/open_group_api/sogsv3/knownBlindedkeys'; -import { QUOTED_TEXT_MAX_LENGTH } from '../session/constants'; +import { DURATION, QUOTED_TEXT_MAX_LENGTH } from '../session/constants'; import { ReactionList } from '../types/Reaction'; import { getAttachmentMetadata } from '../types/message/initializeAttachmentMetadata'; import { expireMessageOnSnode } from '../session/apis/snode_api/expire'; @@ -306,6 +307,24 @@ export class MessageModel extends Backbone.Model { return basicProps; } + public getPropsForExpiringMessage(): PropsForExpiringMessage | null { + const expirationType = this.get('expirationType'); + const expireTimerStart = this.get('expirationStartTimestamp') || null; + const expirationLength = this.get('expireTimer') || null; + const expirationTimestamp = + expirationType && expireTimerStart && expirationLength + ? expireTimerStart + expirationLength * DURATION.SECONDS + : null; + + return { + convoId: this.get('conversationId'), + messageId: this.get('id'), + expirationLength, + expirationTimestamp, + isExpired: this.isExpired(), + }; + } + public getPropsForGroupInvitation(): PropsForGroupInvitation | null { if (!this.isGroupInvitation()) { return null; @@ -333,6 +352,7 @@ export class MessageModel extends Backbone.Model { messageId: this.id as string, receivedAt: this.get('received_at'), isUnread: this.isUnread(), + ...this.getPropsForExpiringMessage(), }; } diff --git a/ts/session/apis/snode_api/SNodeAPI.ts b/ts/session/apis/snode_api/SNodeAPI.ts index 380f04041..e597a743a 100644 --- a/ts/session/apis/snode_api/SNodeAPI.ts +++ b/ts/session/apis/snode_api/SNodeAPI.ts @@ -554,7 +554,7 @@ export async function retrieveNextMessages( handleTimestampOffset('retrieve', json.t); await handleHardforkResult(json); - console.log(`WIP: retrieveNextMessages`, json.messages); + // console.log(`WIP: retrieveNextMessages`, json.messages); return json.messages || []; } catch (e) { diff --git a/ts/session/apis/snode_api/expire.ts b/ts/session/apis/snode_api/expire.ts index eb3b28fb9..bcca1fc40 100644 --- a/ts/session/apis/snode_api/expire.ts +++ b/ts/session/apis/snode_api/expire.ts @@ -30,10 +30,10 @@ async function generateSignature({ `expire${timestamp}${messageHashes.join('')}`, 'utf8' ); - console.log( - `WIP: generateSignature verificationData`, - `expire${timestamp}${messageHashes.join('')}` - ); + // console.log( + // `WIP: generateSignature verificationData`, + // `expire${timestamp}${messageHashes.join('')}` + // ); const message = new Uint8Array(verificationData); const sodium = await getSodiumRenderer(); @@ -76,10 +76,10 @@ async function verifySignature({ `${pubkey.key}${expiryApplied}${messageHashes.join('')}${resultHashes.join('')}`, 'utf8' ); - console.log( - `WIP: verifySignature verificationData`, - `${pubkey.key}${expiryApplied}${messageHashes.join('')}${resultHashes.join('')}` - ); + // console.log( + // `WIP: verifySignature verificationData`, + // `${pubkey.key}${expiryApplied}${messageHashes.join('')}${resultHashes.join('')}` + // ); const sodium = await getSodiumRenderer(); try { @@ -108,10 +108,10 @@ async function processExpirationResults( // TODO need proper typing for swarm and results const results: Record; expiry: number }> = {}; - console.log(`WIP: processExpirationResults`, swarm, messageHashes); + // console.log(`WIP: processExpirationResults`, swarm, messageHashes); for (const nodeKey of Object.keys(swarm)) { - console.log(`WIP: processExpirationResults we got this far`, nodeKey, swarm[nodeKey]); + // console.log(`WIP: processExpirationResults we got this far`, nodeKey, swarm[nodeKey]); if (!isEmpty(swarm[nodeKey].failed)) { const reason = 'Unknown'; const statusCode = '404'; @@ -173,14 +173,9 @@ async function expireOnNodes(targetNode: Snode, params: ExpireParams) { try { const parsed = JSON.parse(result.body); - const expirationResults = await processExpirationResults( - params.pubkey, - targetNode, - parsed.swarm, - params.messages - ); + await processExpirationResults(params.pubkey, targetNode, parsed.swarm, params.messages); - console.log(`WIP: expireOnNodes attempt complete. Here are the results`, expirationResults); + // console.log(`WIP: expireOnNodes attempt complete. Here are the results`, expirationResults); return true; } catch (e) { @@ -198,12 +193,12 @@ async function expireOnNodes(targetNode: Snode, params: ExpireParams) { } export async function expireMessageOnSnode(messageHash: string, expireTimer: number) { - console.log(`WIP: expireMessageOnSnode running!`); + // console.log(`WIP: expireMessageOnSnode running!`); const ourPubKey = UserUtils.getOurPubKeyFromCache(); const ourEd25519Key = await UserUtils.getUserED25519KeyPair(); if (!ourPubKey || !ourEd25519Key) { - window.log.info(`WIP: expireMessageOnSnode failed!`, messageHash); + // window.log.info(`WIP: expireMessageOnSnode failed!`, messageHash); return; } @@ -217,7 +212,7 @@ export async function expireMessageOnSnode(messageHash: string, expireTimer: num }); if (!signResult) { - window.log.info(`WIP: Signing message expiry on swarm failed!`, messageHash); + // window.log.info(`WIP: Signing message expiry on swarm failed!`, messageHash); return; } @@ -248,7 +243,7 @@ export async function expireMessageOnSnode(messageHash: string, expireTimer: num try { const firstSuccessSnode = await firstTrue(promises); snode = firstSuccessSnode; - console.log(`WIP: expireMessageOnSnode firstSuccessSnode`, firstSuccessSnode); + // console.log(`WIP: expireMessageOnSnode firstSuccessSnode`, firstSuccessSnode); } catch (e) { const snodeStr = snode ? `${snode.ip}:${snode.port}` : 'null'; window?.log?.warn( diff --git a/ts/session/messages/outgoing/visibleMessage/GroupInvitationMessage.ts b/ts/session/messages/outgoing/visibleMessage/GroupInvitationMessage.ts index a04deeb06..9f31f87e2 100644 --- a/ts/session/messages/outgoing/visibleMessage/GroupInvitationMessage.ts +++ b/ts/session/messages/outgoing/visibleMessage/GroupInvitationMessage.ts @@ -1,25 +1,30 @@ -import { DataMessage } from '..'; import { SignalService } from '../../../../protobuf'; +import { DisappearingMessageType } from '../../../../util/expiringMessages'; import { MessageParams } from '../Message'; +import { VisibleMessage } from './VisibleMessage'; interface GroupInvitationMessageParams extends MessageParams { url: string; name: string; - // if there is an expire timer set for the conversation, we need to set it. + // if disappearing messages is set for the conversation, we need to set it. // otherwise, it will disable the expire timer on the receiving side. + expirationType?: DisappearingMessageType; expireTimer?: number; } -export class GroupInvitationMessage extends DataMessage { +export class GroupInvitationMessage extends VisibleMessage { private readonly url: string; private readonly name: string; - private readonly expireTimer?: number; constructor(params: GroupInvitationMessageParams) { - super({ timestamp: params.timestamp, identifier: params.identifier }); + super({ + timestamp: params.timestamp, + identifier: params.identifier, + expirationType: params.expirationType, + expireTimer: params.expireTimer, + }); this.url = params.url; this.name = params.name; - this.expireTimer = params.expireTimer; } public dataProto(): SignalService.DataMessage { diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index 967365c60..2b30bf706 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -100,14 +100,6 @@ async function handleMessageSentSuccess( void PnServer.notifyPnServer(wrappedEnvelope, sentMessage.device); } } - if (!shouldMarkMessageAsSynced) { - const expirationType = fetchedMessage.get('expirationType'); - if (expirationType) { - fetchedMessage = - setExpirationStartTimestamp(fetchedMessage, expirationType, effectiveTimestamp) || - fetchedMessage; - } - } // Handle the sync logic here if (shouldTriggerSyncMessage) { @@ -142,6 +134,14 @@ async function handleMessageSentSuccess( sent_at: effectiveTimestamp, }); + if (!shouldMarkMessageAsSynced) { + const expirationType = fetchedMessage.get('expirationType'); + if (expirationType) { + fetchedMessage = + setExpirationStartTimestamp(fetchedMessage, expirationType) || fetchedMessage; + } + } + await fetchedMessage.commit(); fetchedMessage.getConversation()?.updateLastMessage(); } diff --git a/ts/util/expiringMessages.ts b/ts/util/expiringMessages.ts index fcc0c27fb..3d7c9d37c 100644 --- a/ts/util/expiringMessages.ts +++ b/ts/util/expiringMessages.ts @@ -211,17 +211,18 @@ export function setExpirationStartTimestamp( if (timestamp) { expirationStartTimestamp = Math.min(getNowWithNetworkOffset(), timestamp); - message.set('expirationStartTimestamp', expirationStartTimestamp); } + message.set('expirationStartTimestamp', expirationStartTimestamp); + if (mode === 'deleteAfterRead') { window.log.info( - `WIP: setExpirationStartTimestamp we set the start timetamp for a delete after read message`, + `WIP: setExpirationStartTimestamp we set the start timestamp for a delete after read message`, message ); } else if (mode === 'deleteAfterSend') { window.log.info( - `WIP: setExpirationStartTimestamp we set the start timetamp for a delete after send message`, + `WIP: setExpirationStartTimestamp we set the start timestamp for a delete after send message`, message ); } else {