feat: setExpirationStartTimestamp uses DisappearingMessageConversationType

easier to manage starting a legacy disappearing message and always pass expiration type and timer
pull/2971/head
William Grant 2 years ago
parent 82bb74a9df
commit e8c927f580

@ -122,7 +122,6 @@ import {
changeToDisappearingMessageType,
} from '../util/expiringMessages';
import { markAttributesAsReadIfNeeded } from './messageFactory';
import { ReleasedFeatures } from '../util/releaseFeature';
type InMemoryConvoInfos = {
mentionedUs: boolean;
@ -890,13 +889,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
source,
fromSync,
},
// TODO legacy messages support will be removed in a future release
expirationType: ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached()
? messageExpirationType
: undefined,
expireTimer: ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached()
? expireTimer
: undefined,
// TODO Confirm that legacy devices ignore this and that everything works
expirationType: messageExpirationType,
expireTimer,
};
if (!message) {

@ -94,7 +94,6 @@ import {
DisappearingMessageType,
DisappearingMessageUpdate,
ExpirationTimerOptions,
isLegacyDisappearingModeEnabled,
setExpirationStartTimestamp,
changeToDisappearingMessageConversationType,
} from '../util/expiringMessages';
@ -1129,22 +1128,23 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
public markMessageReadNoCommit(readAt: number) {
this.set({ unread: READ_MESSAGE_STATE.read });
const expirationType = this.get('expirationType');
// TODO legacy messages support will be removed in a future release
const convo = this.getConversation();
const isLegacyMode =
convo &&
!convo.isMe() &&
convo.isPrivate() &&
isLegacyDisappearingModeEnabled(expirationType);
if ((isLegacyMode || expirationType === 'deleteAfterRead') && this.get('expireTimer')) {
this.set({
expirationStartTimestamp: setExpirationStartTimestamp(
'deleteAfterRead',
readAt,
isLegacyMode
),
});
const canBeDeleteAfterRead = convo && !convo.isMe() && convo.isPrivate();
const expirationType = this.get('expirationType');
const expireTimer = this.get('expireTimer');
if (canBeDeleteAfterRead && expirationType && expireTimer > 0) {
const expirationMode = changeToDisappearingMessageConversationType(
convo,
expirationType,
expireTimer
);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterRead') {
this.set({
expirationStartTimestamp: setExpirationStartTimestamp(expirationMode, readAt),
});
}
}
Notifications.clearByMessageId(this.id);

@ -39,7 +39,6 @@ import {
changeToDisappearingMessageType,
checkForExpireUpdateInContentMessage,
checkHasOutdatedClient,
isLegacyDisappearingModeEnabled,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
@ -451,12 +450,17 @@ export async function innerHandleSwarmContentMessage(
if (isEmpty(content.dataMessage.profileKey)) {
content.dataMessage.profileKey = null;
}
window.log.debug(`WIP: innerHandleSwarmContentMessage: ${JSON.stringify(content)}`);
const expireUpdate = await checkForExpireUpdateInContentMessage(
conversationModelForUIUpdate,
content
);
window.log.debug(
`WIP:innerHandleSwarmContentMessage expireUpdate: ${JSON.stringify(expireUpdate)}`
);
// TODO legacy messages support will be removed in a future release
if (expireUpdate && !isEmpty(expireUpdate) && expireUpdate.isDisappearingMessagesV2Released) {
await checkHasOutdatedClient(
@ -832,10 +836,22 @@ export async function handleDataExtractionNotification(
if (timestamp) {
const envelopeTimestamp = toNumber(timestamp);
const referencedAttachmentTimestamp = toNumber(referencedAttachment);
const expirationType = convo.get('expirationType');
// TODO legacy messages support will be removed in a future release
const isLegacyMode =
convo && convo.isPrivate() && isLegacyDisappearingModeEnabled(expirationType);
const expirationMode = convo.get('expirationType');
const expireTimer = convo.get('expireTimer');
let expirationType;
let expirationStartTimestamp;
if (convo && expirationMode && expireTimer > 0) {
expirationType =
expirationType !== 'off'
? changeToDisappearingMessageType(convo, expirationMode)
: undefined;
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
expirationStartTimestamp = setExpirationStartTimestamp(expirationMode);
}
}
await convo.addSingleIncomingMessage({
source,
@ -847,16 +863,9 @@ export async function handleDataExtractionNotification(
},
unread: READ_MESSAGE_STATE.unread, // 1 means unread
expirationType:
expirationType !== 'off'
? changeToDisappearingMessageType(convo, expirationType)
: undefined,
expireTimer: convo.get('expireTimer') ? convo.get('expireTimer') : 0,
// TODO should this only be for delete after send?
expirationStartTimestamp:
isLegacyMode || expirationType === 'deleteAfterSend'
? setExpirationStartTimestamp('deleteAfterSend', undefined, isLegacyMode)
: undefined,
expirationType,
expireTimer,
expirationStartTimestamp,
});
convo.updateLastMessage();

@ -263,6 +263,7 @@ export async function handleSwarmDataMessage(
if (!isEmpty(expireUpdate)) {
msgModel = handleExpireUpdate(convoToAddMessageTo, msgModel, expireUpdate);
window.log.debug(`WIP: innerHandleSwarmContentMessage msgModel ${JSON.stringify(msgModel)}`);
}
await handleSwarmMessage(

@ -17,7 +17,6 @@ import { getHideMessageRequestBannerOutsideRedux } from '../state/selectors/user
import { GoogleChrome } from '../util';
import {
changeToDisappearingMessageConversationType,
isLegacyDisappearingModeEnabled,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
import { LinkPreviews } from '../util/linkPreviews';
@ -181,22 +180,23 @@ async function processProfileKeyNoCommit(
function updateReadStatus(message: MessageModel) {
if (message.isExpirationTimerUpdate()) {
message.set({ unread: READ_MESSAGE_STATE.read });
const expirationType = message.get('expirationType');
// TODO legacy messages support will be removed in a future release
const convo = message.getConversation();
const isLegacyMode =
convo &&
!convo.isMe() &&
convo.isPrivate() &&
isLegacyDisappearingModeEnabled(expirationType);
if ((isLegacyMode || expirationType === 'deleteAfterRead') && message.get('expireTimer')) {
message.set({
expirationStartTimestamp: setExpirationStartTimestamp(
'deleteAfterRead',
undefined,
isLegacyMode
),
});
const canBeDeleteAfterRead = convo && !convo.isMe() && convo.isPrivate();
const expirationType = message.get('expirationType');
const expireTimer = message.get('expireTimer');
if (canBeDeleteAfterRead && expirationType && expireTimer > 0) {
const expirationMode = changeToDisappearingMessageConversationType(
convo,
expirationType,
expireTimer
);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterRead') {
message.set({
expirationStartTimestamp: setExpirationStartTimestamp(expirationMode),
});
}
}
}
}
@ -391,21 +391,31 @@ export async function handleMessageJob(
try {
messageModel.set({ flags: regularDataMessage.flags });
// TODO legacy messages support will be removed in a future release
const isLegacyMode = isLegacyDisappearingModeEnabled(messageModel.get('expirationType'));
const expirationType = messageModel.get('expirationType');
const expireTimer = messageModel.get('expireTimer');
// NOTE we handle incoming disappear afer send messages and are Note To Self sync messages here
if (
messageModel.isIncoming() &&
Boolean(messageModel.get('expirationStartTimestamp')) === false &&
((isLegacyMode && (conversation.isMe() || conversation.isClosedGroup())) ||
messageModel.get('expirationType') === 'deleteAfterSend')
conversation &&
(messageModel.isIncoming() || conversation.isMe()) &&
expirationType &&
expireTimer > 0 &&
Boolean(messageModel.get('expirationStartTimestamp')) === false
) {
messageModel.set({
expirationStartTimestamp: setExpirationStartTimestamp(
'deleteAfterSend',
messageModel.get('sent_at'),
isLegacyMode
),
});
const expirationMode = changeToDisappearingMessageConversationType(
conversation,
expirationType,
expireTimer
);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
messageModel.set({
expirationStartTimestamp: setExpirationStartTimestamp(
expirationMode,
messageModel.get('sent_at')
),
});
}
}
if (messageModel.isExpirationTimerUpdate()) {
@ -423,11 +433,11 @@ export async function handleMessageJob(
return;
}
const expireTimer = expirationTimerUpdate?.expireTimer || 0;
const expirationType = changeToDisappearingMessageConversationType(
const expireTimerUpdate = expirationTimerUpdate?.expireTimer || 0;
const expirationTypeUpdate = changeToDisappearingMessageConversationType(
conversation,
expirationTimerUpdate?.expirationType,
expireTimer
expireTimerUpdate
);
const lastDisappearingMessageChangeTimestamp =
expirationTimerUpdate?.lastDisappearingMessageChangeTimestamp ||
@ -435,8 +445,8 @@ export async function handleMessageJob(
// Compare mode and timestamp
if (
isEqual(expirationType, conversation.get('expirationType')) &&
isEqual(expireTimer, conversation.get('expireTimer'))
isEqual(expirationTypeUpdate, conversation.get('expirationType')) &&
isEqual(expireTimerUpdate, conversation.get('expireTimer'))
) {
confirm?.();
window?.log?.info(
@ -446,8 +456,8 @@ export async function handleMessageJob(
}
await conversation.updateExpireTimer({
providedExpirationType: expirationType,
providedExpireTimer: expireTimer,
providedExpirationType: expirationTypeUpdate,
providedExpireTimer: expireTimerUpdate,
providedChangeTimestamp: lastDisappearingMessageChangeTimestamp,
providedSource: source,
receivedAt: messageModel.get('received_at'),

@ -82,7 +82,7 @@ async function processExpirationResults(
// TODO need proper typing for swarm and results
const results: Record<string, { hashes: Array<string>; expiry: number }> = {};
window.log.debug(`WIP: processExpirationResults start`, swarm, messageHashes);
// window.log.debug(`WIP: processExpirationResults start`, swarm, messageHashes);
for (const nodeKey of Object.keys(swarm)) {
if (!isEmpty(swarm[nodeKey].failed)) {

@ -28,7 +28,6 @@ import { fromHexToArray, toHex } from '../utils/String';
import {
DisappearingMessageConversationType,
changeToDisappearingMessageType,
isLegacyDisappearingModeEnabled,
setExpirationStartTimestamp,
} from '../../util/expiringMessages';
@ -164,22 +163,26 @@ export async function addUpdateMessage(
groupUpdate.kicked = diff.kickedMembers;
}
const expirationType = changeToDisappearingMessageType(convo, convo.get('expirationType'));
const expireTimer = convo.get('expireTimer');
const expirationMode = convo.get('expirationType');
const expireTimer = convo.get('expireTimer') || 0;
let expirationType;
let expirationStartTimestamp;
if (convo && expirationMode && expireTimer > 0) {
expirationType =
expirationMode !== 'off' ? changeToDisappearingMessageType(convo, expirationMode) : undefined;
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, sentAt);
}
}
const msgModel = {
sent_at: sentAt,
group_update: groupUpdate,
expirationType: expirationType || undefined,
expireTimer: expireTimer || 0,
// closed groups are always deleteAfterSend
expirationStartTimestamp: expirationType
? setExpirationStartTimestamp(
'deleteAfterSend',
sentAt,
isLegacyDisappearingModeEnabled(expirationType)
)
: undefined,
expirationType,
expireTimer,
expirationStartTimestamp,
};
if (UserUtils.isUsFromCache(sender)) {

@ -30,7 +30,7 @@ export class ExpirableMessage extends ContentMessage {
? SignalService.Content.ExpirationType.DELETE_AFTER_SEND
: this.expirationType === 'deleteAfterRead'
? SignalService.Content.ExpirationType.DELETE_AFTER_READ
: this.expirationType
: this.expirationType === 'unknown'
? SignalService.Content.ExpirationType.UNKNOWN
: undefined,
expirationTimer: this.expireTimer && this.expireTimer > -1 ? this.expireTimer : undefined,
@ -40,7 +40,12 @@ export class ExpirableMessage extends ContentMessage {
public dataProto(): SignalService.DataMessage {
return new SignalService.DataMessage({
// TODO legacy messages support will be removed in a future release
expireTimer: !this.expirationType ? this.expireTimer : undefined,
expireTimer:
(this.expirationType === 'unknown' || !this.expirationType) &&
this.expireTimer &&
this.expireTimer > -1
? this.expireTimer
: undefined,
});
}

@ -2,7 +2,7 @@ import _ from 'lodash';
import { Data } from '../../data/data';
import { SignalService } from '../../protobuf';
import {
isLegacyDisappearingModeEnabled,
changeToDisappearingMessageConversationType,
setExpirationStartTimestamp,
} from '../../util/expiringMessages';
import { PnServer } from '../apis/push_notification_api';
@ -124,40 +124,37 @@ async function handleMessageSentSuccess(
sentTo = _.union(sentTo, [sentMessage.device]);
const expirationType = fetchedMessage.get('expirationType');
// TODO legacy messages support will be removed in a future release
const convo = fetchedMessage.getConversation();
const isLegacyMode = isLegacyDisappearingModeEnabled(expirationType);
const isLegacyReadMode = convo && !convo.isMe() && convo.isPrivate() && isLegacyMode;
const isLegacySentMode = convo && (convo.isMe() || convo.isClosedGroup()) && isLegacyMode;
fetchedMessage.set({
sent_to: sentTo,
sent: true,
sent_at: effectiveTimestamp,
});
// TODO legacy messages support will be removed in a future release
// NOTE we treat all outbound disappearing messages as read as soon as they are sent.
const convo = fetchedMessage.getConversation();
const expireTimer = fetchedMessage.get('expireTimer');
const expirationType = fetchedMessage.get('expirationType');
if (
(isLegacyReadMode ||
isLegacySentMode ||
expirationType === 'deleteAfterRead' ||
expirationType === 'deleteAfterSend') &&
convo &&
expirationType &&
expireTimer > 0 &&
Boolean(fetchedMessage.get('expirationStartTimestamp')) === false
) {
const expirationMode =
isLegacyReadMode || expirationType === 'deleteAfterRead'
? 'deleteAfterRead'
: 'deleteAfterSend';
fetchedMessage.set({
expirationStartTimestamp: setExpirationStartTimestamp(
expirationMode,
fetchedMessage.get('sent_at'),
isLegacyReadMode || isLegacySentMode
),
});
const expirationMode = changeToDisappearingMessageConversationType(
convo,
expirationType,
expireTimer
);
// NOTE we treat all outbound disappearing messages as read as soon as they are sent.
if (expirationMode !== 'off') {
fetchedMessage.set({
expirationStartTimestamp: setExpirationStartTimestamp(
expirationMode,
fetchedMessage.get('sent_at')
),
});
}
}
await fetchedMessage.commit();

@ -35,7 +35,6 @@ import { SnodeNamespaces } from '../../apis/snode_api/namespaces';
import { READ_MESSAGE_STATE } from '../../../models/conversationAttributes';
import {
changeToDisappearingMessageType,
isLegacyDisappearingModeEnabled,
setExpirationStartTimestamp,
} from '../../../util/expiringMessages';
@ -517,22 +516,25 @@ export async function USER_callRecipient(recipient: string) {
await calledConvo.unhideIfNeeded(false);
weAreCallerOnCurrentCall = true;
// TODO legacy messages support will be removed in a future release
const isLegacyMode = isLegacyDisappearingModeEnabled(calledConvo.get('expirationType'));
const expirationType = changeToDisappearingMessageType(
calledConvo,
calledConvo.get('expirationType')
);
const expirationMode = calledConvo.get('expirationType');
const expireTimer = calledConvo.get('expireTimer') || 0;
let expirationType;
let expirationStartTimestamp;
if (calledConvo && expirationMode && expireTimer > 0) {
expirationType = changeToDisappearingMessageType(calledConvo, expirationMode);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, now);
}
}
await calledConvo?.addSingleOutgoingMessage({
callNotificationType: 'started-call',
sent_at: now,
expirationType: calledConvo.get('expireTimer') > 0 ? expirationType : undefined,
expireTimer: calledConvo.get('expireTimer') ? calledConvo.get('expireTimer') : 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? now : undefined,
isLegacyMode
),
expirationType,
expireTimer,
expirationStartTimestamp,
});
// initiating a call is analogous to sending a message request
@ -894,25 +896,28 @@ export async function USER_acceptIncomingCallRequest(fromSender: string) {
callerConvo.set('active_at', networkTimestamp);
await callerConvo.unhideIfNeeded(false);
// TODO legacy messages support will be removed in a future release
const isLegacyMode = isLegacyDisappearingModeEnabled(callerConvo.get('expirationType'));
const expirationType = changeToDisappearingMessageType(
callerConvo,
callerConvo.get('expirationType')
);
const expirationMode = callerConvo.get('expirationType');
const expireTimer = callerConvo.get('expireTimer') || 0;
let expirationType;
let expirationStartTimestamp;
if (callerConvo && expirationMode && expireTimer > 0) {
expirationType = changeToDisappearingMessageType(callerConvo, expirationMode);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, networkTimestamp);
}
}
await callerConvo?.addSingleIncomingMessage({
callNotificationType: 'answered-a-call',
source: UserUtils.getOurPubKeyStrFromCache(),
sent_at: networkTimestamp,
received_at: networkTimestamp,
unread: READ_MESSAGE_STATE.read,
expirationType: callerConvo.get('expireTimer') > 0 ? expirationType : undefined,
expireTimer: callerConvo.get('expireTimer') ? callerConvo.get('expireTimer') : 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? networkTimestamp : undefined,
isLegacyMode
),
expirationType,
expireTimer,
expirationStartTimestamp,
});
await buildAnswerAndSendIt(fromSender);
@ -1243,29 +1248,28 @@ async function addMissedCallMessage(callerPubkey: string, sentAt: number) {
await incomingCallConversation.unhideIfNeeded(false);
}
// TODO legacy messages support will be removed in a future release
const isLegacyMode = isLegacyDisappearingModeEnabled(
incomingCallConversation.get('expirationType')
);
const expirationType = changeToDisappearingMessageType(
incomingCallConversation,
incomingCallConversation.get('expirationType')
);
const expirationMode = incomingCallConversation.get('expirationType');
const expireTimer = incomingCallConversation.get('expireTimer') || 0;
let expirationType;
let expirationStartTimestamp;
if (incomingCallConversation && expirationMode && expireTimer > 0) {
expirationType = changeToDisappearingMessageType(incomingCallConversation, expirationMode);
if (expirationMode === 'legacy' || expirationMode === 'deleteAfterSend') {
expirationStartTimestamp = setExpirationStartTimestamp(expirationMode, sentAt);
}
}
await incomingCallConversation?.addSingleIncomingMessage({
callNotificationType: 'missed-call',
source: callerPubkey,
sent_at: sentAt,
received_at: GetNetworkTime.getNowWithNetworkOffset(),
unread: READ_MESSAGE_STATE.unread,
expirationType: incomingCallConversation.get('expireTimer') > 0 ? expirationType : undefined,
expireTimer: incomingCallConversation.get('expireTimer')
? incomingCallConversation.get('expireTimer')
: 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? sentAt : undefined,
isLegacyMode
),
expirationType,
expireTimer,
expirationStartTimestamp,
});
}

@ -239,18 +239,15 @@ export const ExpirationTimerOptions = {
};
export function setExpirationStartTimestamp(
mode: DisappearingMessageType,
timestamp?: number,
isLegacyMode?: boolean
mode: DisappearingMessageConversationType,
timestamp?: number
): number | undefined {
let expirationStartTimestamp: number | undefined = GetNetworkTime.getNowWithNetworkOffset();
// TODO legacy messages support will be removed in a future release
if (timestamp) {
window.log.debug(
`We compare 2 timestamps for a disappear ${
isLegacyMode ? 'legacy' : mode === 'deleteAfterRead' ? 'after read' : 'after send'
} message: expirationStartTimestamp `,
`WIP: We compare 2 timestamps for a disappearing message (${mode}): expirationStartTimestamp `,
new Date(expirationStartTimestamp).toLocaleTimeString(),
'\ntimestamp ',
new Date(timestamp).toLocaleTimeString()
@ -261,24 +258,28 @@ export function setExpirationStartTimestamp(
// TODO legacy messages support will be removed in a future release
if (mode === 'deleteAfterRead') {
window.log.debug(
`We set the start timestamp for a ${
isLegacyMode ? 'legacy ' : ''
}delete after read message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}`
`WIP: We set the start timestamp for a delete after read message to ${new Date(
expirationStartTimestamp
).toLocaleTimeString()}`
);
} else if (mode === 'deleteAfterSend') {
window.log.debug(
`We set the start timestamp for a ${
isLegacyMode ? 'legacy ' : ''
}delete after send message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}`
`WIP: We set the start timestamp for a delete after send message to ${new Date(
expirationStartTimestamp
).toLocaleTimeString()}`
);
// TODO needs improvement
} else if (mode === 'unknown') {
} else if (mode === 'legacy') {
window.log.debug(
`Disappearing message mode "${mode}"set. This could be a legacy message or we are turning off disappearing messages`
`WIP: We set the start timestamp for a legacy message to ${new Date(
expirationStartTimestamp
).toLocaleTimeString()}`
);
} else if (mode === 'off') {
window.log.debug('Disappearing message mode has been turned off. We can safely ignore this.');
expirationStartTimestamp = undefined;
} else {
window.log.debug(`Invalid disappearing message mode "${mode}" set. Ignoring`);
window.log.debug(`WIP: Invalid disappearing message mode "${mode}" set. Ignoring`);
expirationStartTimestamp = undefined;
}
@ -372,6 +373,7 @@ export async function checkForExpireUpdateInContentMessage(
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();
// debugger;
const isLegacyContentMessage = checkIsLegacyContentMessage(content);
const isLegacyDataMessage = Boolean(

Loading…
Cancel
Save