feat: added hasOutdated Client to convo model, use feature release check to process disappearing messages

trigger banner when receiving a legacy disappearing message via hasOutdatedClient
pull/2660/head
William Grant 3 years ago
parent e81ac0a847
commit bd900128f4

@ -255,7 +255,7 @@ export class SessionConversation extends React.Component<Props, State> {
<SessionTheme>
<div className="conversation-header">
<ConversationHeaderWithDetails />
{selectedConversation.expirationType === 'legacy' && (
{selectedConversation?.hasOutdatedClient && (
<NoticeBanner
text={window.i18n('disappearingMessagesModeOutdated', [
selectedConversation?.nickname ||

@ -300,6 +300,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const left = !!this.get('left');
const expirationType = this.get('expirationType');
const expireTimer = this.get('expireTimer');
const lastDisappearingMessageChangeTimestamp = this.get(
'lastDisappearingMessageChangeTimestamp'
);
const hasOutdatedClient = this.get('hasOutdatedClient');
const currentNotificationSetting = this.get('triggerNotificationsFor');
const displayNameInProfile = this.get('displayNameInProfile');
const nickname = this.get('nickname');
@ -414,6 +418,14 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
toRet.expireTimer = expireTimer;
}
if (lastDisappearingMessageChangeTimestamp) {
toRet.lastDisappearingMessageChangeTimestamp = lastDisappearingMessageChangeTimestamp;
}
if (hasOutdatedClient) {
toRet.hasOutdatedClient = hasOutdatedClient;
}
if (
currentNotificationSetting &&
currentNotificationSetting !== ConversationNotificationSetting[0]

@ -35,6 +35,8 @@ export interface ConversationAttributes {
expireTimer: number;
lastDisappearingMessageChangeTimestamp: number;
hasOutdatedClient: boolean;
mentionedUs: boolean;
unreadCount: number;
lastMessageStatus: LastMessageStatusType;
@ -89,9 +91,12 @@ export const fillConvoAttributesWithDefaults = (
unreadCount: 0,
lastJoinedTimestamp: 0,
subscriberCount: 0,
expirationType: 'off',
expireTimer: 0,
lastDisappearingMessageChangeTimestamp: 0,
hasOutdatedClient: false,
active_at: 0,
lastMessageStatus: undefined,

@ -78,6 +78,7 @@ const allowedKeysFormatRowOfConversation = [
'conversationIdOrigin',
'expirationType',
'lastDisappearingMessageChangeTimestamp',
'hasOutdatedClient',
];
export function formatRowOfConversation(row?: Record<string, any>): ConversationAttributes | null {
@ -133,6 +134,7 @@ export function formatRowOfConversation(row?: Record<string, any>): Conversation
convo.readCapability = Boolean(convo.readCapability);
convo.writeCapability = Boolean(convo.writeCapability);
convo.uploadCapability = Boolean(convo.uploadCapability);
convo.hasOutdatedClient = Boolean(convo.hasOutdatedClient);
if (!convo.conversationIdOrigin) {
convo.conversationIdOrigin = undefined;
@ -208,6 +210,7 @@ const allowedKeysOfConversationAttributes = [
'conversationIdOrigin',
'expirationType',
'lastDisappearingMessageChangeTimestamp',
'hasOutdatedClient',
];
/**

@ -1223,6 +1223,10 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN lastDisappearingMessageChangeTimestamp INTEGER DEFAULT 0;`
).run();
db.prepare(
`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN hasOutdatedClient BOOLEAN DEFAULT false;`
).run();
// same value in ts/util/releaseFeature.ts but we cannot import since window doesn't exist yet.
// TODO update to agreed value between platforms
const featureReleaseTimestamp = 1677574800000; // unix 28/02/2023 09:00

@ -440,6 +440,7 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
// TODO rename expireTimer to expirationTimer
expireTimer,
lastDisappearingMessageChangeTimestamp,
hasOutdatedClient,
mentionedUs,
unreadCount,
lastMessageStatus,
@ -486,6 +487,7 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp,
hasOutdatedClient,
mentionedUs,
unreadCount,
lastMessageStatus,
@ -521,6 +523,7 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
$expirationType,
$expireTimer,
$lastDisappearingMessageChangeTimestamp,
$hasOutdatedClient,
$mentionedUs,
$unreadCount,
$lastMessageStatus,
@ -558,6 +561,7 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp,
hasOutdatedClient: toSqliteBoolean(hasOutdatedClient),
mentionedUs: toSqliteBoolean(mentionedUs),
unreadCount,
lastMessageStatus,
@ -2352,6 +2356,7 @@ function fillWithTestData(numConvosToAdd: number, numMsgsToAdd: number) {
expirationType: 'off',
expireTimer: 0,
lastDisappearingMessageChangeTimestamp: 0,
hasOutdatedClient: false,
groupAdmins: [],
groupModerators: [],
isApproved: false,

@ -33,6 +33,7 @@ import {
DisappearingMessageUpdate,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
import { checkIsFeatureReleased } from '../util/releaseFeature';
export async function handleSwarmContentMessage(envelope: EnvelopePlus, messageHash: string) {
try {
@ -407,24 +408,40 @@ export async function innerHandleSwarmContentMessage(
perfStart(`handleSwarmDataMessage-${envelope.id}`);
// TODO Trigger banner in UI?
// TODO maybe trigger the banner later based on the expirationType for the conversation
const isLegacyMode = dataMessage.expireTimer && dataMessage.expireTimer > 0;
if (isLegacyMode) {
window.log.info('WIP: Received legacy disappearing message', content);
// We will only support legacy disappearing messages for a short period before disappearing messages v2 is unlocked
const isDisappearingMessagesV2Released = await checkIsFeatureReleased(
'Disappearing Messages V2'
);
const isLegacyMessage = Boolean(dataMessage.expireTimer && dataMessage.expireTimer > 0);
// TODO account for outdated groups separately probably
if (isLegacyMessage) {
window.log.info('WIP: Received a legacy disappearing message', content);
// trigger notice banner
if (!senderConversationModel.get('hasOutdatedClient')) {
senderConversationModel.set({ hasOutdatedClient: true });
}
} else {
if (senderConversationModel.get('hasOutdatedClient')) {
senderConversationModel.set({ hasOutdatedClient: false });
}
}
// TODO legacy messages support will be removed in a future release
const expireUpdate: DisappearingMessageUpdate = {
// TODO When sending a message if it's a legacy message then we need to set the type to the default for compatiblity reasons
expirationType: isLegacyMode
? DisappearingMessageConversationSetting[3]
: DisappearingMessageConversationSetting[content.expirationType] || 'off',
// TODO in the future we will remove the dataMessage expireTimer
expireTimer: isLegacyMode ? Number(dataMessage.expireTimer) : content.expirationTimer,
expirationType:
!isDisappearingMessagesV2Released && isLegacyMessage
? DisappearingMessageConversationSetting[3]
: DisappearingMessageConversationSetting[content.expirationType] || 'off',
expireTimer:
!isDisappearingMessagesV2Released && isLegacyMessage
? Number(dataMessage.expireTimer)
: content.expirationTimer,
lastDisappearingMessageChangeTimestamp: content.lastDisappearingMessageChangeTimestamp
? Number(content.lastDisappearingMessageChangeTimestamp)
: undefined,
isLegacyMessage,
isDisappearingMessagesV2Released,
};
await handleSwarmDataMessage(

@ -247,22 +247,52 @@ export async function handleSwarmDataMessage(
// TODO handle sync messages separately
window.log.info('WIP: Sync Message dropping');
} else {
const { expirationType, expireTimer, lastDisappearingMessageChangeTimestamp } = expireUpdate;
msgModel.set({
const {
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp,
isLegacyMessage,
isDisappearingMessagesV2Released,
} = expireUpdate;
// TODO legacy messages support will be removed in a future release
msgModel.set({
expirationType: isDisappearingMessagesV2Released
? senderConversationModel.get('expirationType')
: expirationType,
expireTimer: isDisappearingMessagesV2Released
? senderConversationModel.get('expireTimer')
: expireTimer,
});
// TODO legacy messages support will be removed in a future release
// This message is conversation setting change message
if (lastDisappearingMessageChangeTimestamp) {
if (
lastDisappearingMessageChangeTimestamp ||
(isLegacyMessage &&
rawDataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE)
) {
const expirationTimerUpdate = {
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp: isLegacyMessage
? Date.now()
: Number(lastDisappearingMessageChangeTimestamp),
source: msgModel.get('source'),
};
if (isLegacyMessage && isDisappearingMessagesV2Released) {
// if it is a legacy message then we ignore it and use the local client's conversation settings
expirationTimerUpdate.expirationType = senderConversationModel.get('expirationType');
expirationTimerUpdate.expireTimer = senderConversationModel.get('expireTimer');
expirationTimerUpdate.lastDisappearingMessageChangeTimestamp = senderConversationModel.get(
'lastDisappearingMessageChangeTimestamp'
);
}
msgModel.set({
expirationTimerUpdate: {
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp,
source: msgModel.get('source'),
},
expirationTimerUpdate,
});
}
}

@ -16,10 +16,7 @@ import { GoogleChrome } from '../util';
import { appendFetchAvatarAndProfileJob } from './userProfileImageUpdates';
import { ConversationTypeEnum } from '../models/conversationAttributes';
import { getUsBlindedInThatServer } from '../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import {
DisappearingMessageConversationType,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
import { setExpirationStartTimestamp } from '../util/expiringMessages';
import { getNowWithNetworkOffset } from '../session/apis/snode_api/SNodeAPI';
function contentTypeSupported(type: string): boolean {
@ -309,25 +306,6 @@ async function handleRegularMessage(
});
}
async function handleExpirationTimerUpdateNoCommit(
conversation: ConversationModel,
message: MessageModel,
source: string,
expirationType: DisappearingMessageConversationType,
expireTimer: number,
lastDisappearingMessageChangeTimestamp: number
) {
await conversation.updateExpireTimer({
providedExpirationType: expirationType,
providedExpireTimer: expireTimer,
providedChangeTimestamp: lastDisappearingMessageChangeTimestamp,
providedSource: source,
receivedAt: message.get('received_at'),
shouldCommit: false,
existingMessage: message,
});
}
export async function handleMessageJob(
messageModel: MessageModel,
conversation: ConversationModel,
@ -349,10 +327,12 @@ export async function handleMessageJob(
try {
messageModel.set({ flags: regularDataMessage.flags });
// TODO legacy messages support will be removed in a future release
if (
messageModel.isIncoming() &&
messageModel.get('expirationType') === 'deleteAfterSend' &&
Boolean(messageModel.get('expirationStartTimestamp')) === false
Boolean(messageModel.get('expirationStartTimestamp')) === false &&
((messageModel.get('expirationType') === 'legacy' && conversation.isGroup()) ||
messageModel.get('expirationType') === 'deleteAfterSend')
) {
messageModel.set({
expirationStartTimestamp: setExpirationStartTimestamp(
@ -385,14 +365,15 @@ export async function handleMessageJob(
return;
}
await handleExpirationTimerUpdateNoCommit(
conversation,
messageModel,
source,
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp
);
await conversation.updateExpireTimer({
providedExpirationType: expirationType,
providedExpireTimer: expireTimer,
providedChangeTimestamp: lastDisappearingMessageChangeTimestamp,
providedSource: source,
receivedAt: messageModel.get('received_at'),
shouldCommit: false,
existingMessage: messageModel,
});
} else {
// this does not commit to db nor UI unless we need to approve a convo
await handleRegularMessage(

@ -262,7 +262,7 @@ export interface ReduxConversationType {
expirationType?: DisappearingMessageConversationType;
expireTimer?: number;
lastDisappearingMessageChangeTimestamp?: number;
hasOutdatedClient?: boolean;
isTyping?: boolean;
isBlocked?: boolean;
isKickedFromGroup?: boolean;

@ -22,6 +22,8 @@ export type DisappearingMessageUpdate = {
expireTimer: number;
// This is used for the expirationTimerUpdate
lastDisappearingMessageChangeTimestamp?: number;
isLegacyMessage?: boolean;
isDisappearingMessagesV2Released?: boolean;
};
export async function destroyMessagesAndUpdateRedux(

Loading…
Cancel
Save