feat: handle legacy disappearing messages more gracefully due to protobuf issues

added utility function for checking for undefined properties on a protobuf, renamed expireTimer to expirationTimer in some places
pull/2660/head
William Grant 1 year ago
parent 4c4bc045d7
commit 6dd340ca6c

@ -1109,7 +1109,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
: isLegacyMessage
? DisappearingMessageConversationSetting[3]
: 'off';
const expireTimer = isLegacyMessage
const expirationTimer = isLegacyMessage
? Number(dataMessage.expireTimer)
: content.expirationTimer;
const lastDisappearingMessageChangeTimestamp = content.lastDisappearingMessageChangeTimestamp
@ -1117,10 +1117,10 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
: undefined;
let expireUpdate: DisappearingMessageUpdate | null = null;
if (expirationType && expireTimer !== undefined) {
if (expirationType && expirationTimer !== undefined) {
expireUpdate = {
expirationType,
expireTimer,
expirationTimer,
lastDisappearingMessageChangeTimestamp,
};
}

@ -1226,8 +1226,8 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
db.prepare(`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN hasOutdatedClient TEXT;`).run();
// TODO update to agreed value between platforms
const disappearingMessagesV2ReleaseTimestamp = 1680339600000; // unix 01/04/2023 09:00
// const disappearingMessagesV2ReleaseTimestamp = 1677488400000; // unix 27/02/2023 09:00
// const disappearingMessagesV2ReleaseTimestamp = 1680339600000; // unix 01/04/2023 09:00
const disappearingMessagesV2ReleaseTimestamp = 1677488400000; // unix 27/02/2023 09:00
// support disppearing messages legacy mode until after the platform agreed timestamp
if (Date.now() < disappearingMessagesV2ReleaseTimestamp) {

@ -1,3 +1,4 @@
import { signalservice as SignalService } from './compiled';
import { ProtobufUtils } from './utils';
export { SignalService };
export { SignalService, ProtobufUtils };

@ -0,0 +1,15 @@
/**
* This function is used to check that an optional property on a Protobuf object is not undefined or using a type-specific default value.
* https://protobuf.dev/programming-guides/proto/#optional
*
* @param object - A Protobuf/JavaScript object
* @param property - The property you want make sure is not undefined
* @returns true if the property is defined or false if undefined or using a type-specific default value
*/
function hasDefinedProperty<A extends {}, B extends PropertyKey & keyof A>(object: A, property: B) {
return object.hasOwnProperty(property) !== false;
}
export const ProtobufUtils = {
hasDefinedProperty,
};

@ -31,6 +31,7 @@ import { appendFetchAvatarAndProfileJob } from './userProfileImageUpdates';
import {
DisappearingMessageConversationSetting,
DisappearingMessageUpdate,
DisappearingMessageUtils,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
import { checkIsFeatureReleased } from '../util/releaseFeature';
@ -409,43 +410,55 @@ export async function innerHandleSwarmContentMessage(
dataMessage.profileKey = null;
}
// debugger;
// TODO legacy messages support will be removed in a future release
// 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 isLegacy = Boolean(
(!content.expirationType && !content.expirationTimer) ||
content.expirationType === SignalService.Content.ExpirationType.UNKNOWN
);
const isLegacyContentMessage = DisappearingMessageUtils.isLegacyContentMessage(content);
const isLegacyMessage = Boolean(
isLegacy && dataMessage.expireTimer && dataMessage.expireTimer > -1
isLegacyContentMessage &&
DisappearingMessageUtils.isLegacyDataMessage(dataMessage as SignalService.DataMessage)
);
// NOTE When a legacy client sends a Conversation Setting Message dataMessage.expirationType and dataMessage.expireTimer can possibly be undefined.
const isLegacyConversationSettingMessage = Boolean(
isLegacy && dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE
isLegacyContentMessage &&
dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE
);
const expireTimer = isDisappearingMessagesV2Released
debugger;
let expirationTimer = isDisappearingMessagesV2Released
? content.expirationTimer
: isLegacyMessage
? Number(dataMessage.expireTimer)
: 0;
: content.expirationTimer;
// TODO legacy messages support will be removed in a future release
const expirationType = isDisappearingMessagesV2Released
? DisappearingMessageConversationSetting[isLegacy ? 3 : content.expirationType]
: isLegacyMessage && expireTimer > 0
? DisappearingMessageConversationSetting[3]
: 'off';
// TODO so close! just have to fix the case of turning off disappearing messages in modern clients. Probably if the timer is zero then override any settings.
let expirationType =
expirationTimer === 0
? 'off'
: isDisappearingMessagesV2Released
? DisappearingMessageConversationSetting[
isLegacyContentMessage ? 3 : content.expirationType
]
: DisappearingMessageConversationSetting[3];
const lastDisappearingMessageChangeTimestamp = content.lastDisappearingMessageChangeTimestamp
? Number(content.lastDisappearingMessageChangeTimestamp)
: undefined;
// TODO legacy messages support will be removed in a future release
// if it is a legacy message and disappearing messages v2 is released then we ignore it and use the local client's conversation settings
if (isDisappearingMessagesV2Released && isLegacyContentMessage) {
window.log.info(`WIP: received a legacy disappearing message after v2 was released.`);
expirationType = conversationModelForUIUpdate.get('expirationType');
expirationTimer = conversationModelForUIUpdate.get('expireTimer');
}
const expireUpdate: DisappearingMessageUpdate = {
expirationType,
expireTimer,
expirationTimer,
lastDisappearingMessageChangeTimestamp,
isLegacyConversationSettingMessage,
isLegacyMessage,

@ -249,21 +249,13 @@ export async function handleSwarmDataMessage(
} else {
let {
expirationType,
expireTimer,
// TODO renamed expireTimer to expirationTimer
expirationTimer: expireTimer,
lastDisappearingMessageChangeTimestamp,
isLegacyConversationSettingMessage,
isLegacyMessage,
isDisappearingMessagesV2Released,
} = expireUpdate;
// TODO legacy messages support will be removed in a future release
// if it is a legacy message and disappearing messages v2 is released then we ignore it and use the local client's conversation settings
if (isDisappearingMessagesV2Released && isLegacyMessage) {
window.log.info(`WIP: received a legacy disappearing message after v2 was released.`);
expirationType = convoToAddMessageTo.get('expirationType');
expireTimer = convoToAddMessageTo.get('expireTimer');
}
msgModel.set({
expirationType,
expireTimer,

@ -328,8 +328,6 @@ export async function handleMessageJob(
) || messageModel.get('timestamp')} in conversation ${conversation.idForLogging()}`
);
window.log.info(`WIP: handleMessageJob()`, messageModel, conversation, regularDataMessage);
const sendingDeviceConversation = await getConversationController().getOrCreateAndWait(
source,
ConversationTypeEnum.PRIVATE

@ -300,7 +300,12 @@ const buildSyncExpireTimerMessage = (
timestamp: number,
syncTarget: string
) => {
const { expirationType, expireTimer, lastDisappearingMessageChangeTimestamp } = expireUpdate;
const {
expirationType,
// TODO rename expireTimer to expirationTimer
expirationTimer: expireTimer,
lastDisappearingMessageChangeTimestamp,
} = expireUpdate;
return new ExpirationTimerUpdateMessage({
identifier,

@ -8,6 +8,7 @@ import { initWallClockListener } from './wallClockListener';
import { Data } from '../data/data';
import { getConversationController } from '../session/conversations';
import { getNowWithNetworkOffset } from '../session/apis/snode_api/SNodeAPI';
import { ProtobufUtils, SignalService } from '../protobuf';
// TODO Might need to be improved by using an enum
// TODO do we need to add legacy here now that it's explicitly in the protbuf?
@ -24,8 +25,7 @@ export const DEFAULT_TIMER_OPTION = {
export type DisappearingMessageUpdate = {
expirationType: DisappearingMessageType;
// TODO rename to expirationTimer?
expireTimer: number;
expirationTimer: number;
// This is used for the expirationTimerUpdate
lastDisappearingMessageChangeTimestamp?: number;
isLegacyConversationSettingMessage?: boolean;
@ -33,6 +33,27 @@ export type DisappearingMessageUpdate = {
isDisappearingMessagesV2Released?: boolean;
};
// TODO legacy messages support will be removed in a future release
// NOTE We need this to check for legacy disappearing messages where the expirationType and expireTimer should be undefined on the ContentMessage
function isLegacyContentMessage(contentMessage: SignalService.Content): boolean {
return (
(contentMessage.expirationType === SignalService.Content.ExpirationType.UNKNOWN ||
!ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationType')) &&
!ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationTimer')
);
}
function isLegacyDataMessage(dataMessage: SignalService.DataMessage): boolean {
return (
ProtobufUtils.hasDefinedProperty(dataMessage, 'expireTimer') && dataMessage.expireTimer > -1
);
}
export const DisappearingMessageUtils = {
isLegacyContentMessage,
isLegacyDataMessage,
};
export async function destroyMessagesAndUpdateRedux(
messages: Array<{
conversationKey: string;

@ -1,8 +1,8 @@
import { Data } from '../data/data';
// TODO update to agreed value between platforms
const featureReleaseTimestamp = 1680339600000; // unix 01/04/2023 09:00
// const featureReleaseTimestamp = 1677488400000; // unix 27/02/2023 09:00
// const featureReleaseTimestamp = 1680339600000; // unix 01/04/2023 09:00
const featureReleaseTimestamp = 1677488400000; // unix 27/02/2023 09:00
let isFeatureReleased: boolean | undefined;
/**

Loading…
Cancel
Save