feat: add cleanup of old expire update in history

we only keep one from each sender
This commit is contained in:
Audric Ackermann 2023-12-06 11:46:49 +11:00
parent 543c80bbe3
commit 19e9e0311e
19 changed files with 211 additions and 110 deletions

View File

@ -192,10 +192,10 @@
"followSetting": "Follow Setting",
"followSettingDisabled": "Messages you send will no longer disappear. Are you sure you want to turn off disappearing messages?",
"followSettingTimeAndType": "Set your messages to disappear $time$ after they have been $type$?",
"youChangedTheTimer": "You have set messages to disappear $time$ after they have been $mode$",
"youChangedTheTimerLegacy": "You set the disappearing message timer to $time$",
"theyChangedTheTimer": "$name$ has set messages to disappear $time$ after they have been $mode$",
"theyChangedTheTimerLegacy": "$name$ set the disappearing message timer to $time$",
"youChangedTheTimer": "<b>You</b> have set messages to disappear <b>$time$</b> after they have been <b>$mode$</b>",
"youChangedTheTimerLegacy": "<b>You<b> set the disappearing message timer to <b>$time$</b>",
"theyChangedTheTimer": "<b>$name$</b> has set messages to disappear <b>$time$</b> after they have been <b>$mode$</b>",
"theyChangedTheTimerLegacy": "<b>$name$</b> set the disappearing message timer to <b>$time$</b>",
"timerOption_0_seconds": "Off",
"timerOption_5_seconds": "5 seconds",
"timerOption_10_seconds": "10 seconds",
@ -233,12 +233,12 @@
"disappearingMessagesModeLegacy": "Legacy",
"disappearingMessagesModeLegacySubtitle": "Original version of disappearing messages.",
"disappearingMessagesDisabled": "Disappearing messages disabled",
"disabledDisappearingMessages": "$name$ has turned off disappearing messages.",
"youDisabledDisappearingMessages": "You have turned off disappearing messages.",
"youDisabledYourDisappearingMessages": "You turned off disappearing messages. Messages you send will no longer disappear.",
"youSetYourDisappearingMessages": "You set your messages to disappear $time$ after they have been $type$.",
"theyDisabledTheirDisappearingMessages": "$name$ has turned off disappearing messages. Messages they send will no longer disappear.",
"theySetTheirDisappearingMessages": "$name$ has set their messages to disappear $time$ after they have been $type$.",
"disabledDisappearingMessages": "<b>$name$</b> has turned <b>off</b> disappearing messages.",
"youDisabledDisappearingMessages": "<b>You</b> have turned <b>off</b> disappearing messages.",
"youDisabledYourDisappearingMessages": "<b>You</b> turned <b>off</b> disappearing messages. Messages you send will no longer disappear.",
"youSetYourDisappearingMessages": "<b>You</b> set your messages to disappear <b>$time$</b> after they have been <b>$type$</b>.",
"theyDisabledTheirDisappearingMessages": "<b>$name$</b> has turned <b>off</b> disappearing messages. Messages they send will no longer disappear.",
"theySetTheirDisappearingMessages": "<b>$name$</b> has set their messages to disappear <b>$time$</b> after they have been <b>$type$</b>.",
"timerSetTo": "Disappearing message time set to $time$",
"set": "Set",
"changeNickname": "Change Nickname",

View File

@ -95,7 +95,7 @@
"glob": "7.1.2",
"image-type": "^4.1.0",
"ip2country": "1.0.1",
"libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.0/libsession_util_nodejs-v0.3.0.tar.gz",
"libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.1/libsession_util_nodejs-v0.3.1.tar.gz",
"libsodium-wrappers-sumo": "^0.7.9",
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",

View File

@ -10,7 +10,7 @@ type TextProps = {
ellipsisOverflow?: boolean;
};
const StyledDefaultText = styled.div<TextProps>`
const StyledDefaultText = styled.div<Omit<TextProps, 'text'>>`
transition: var(--default-duration);
max-width: ${props => (props.maxWidth ? props.maxWidth : '')};
padding: ${props => (props.padding ? props.padding : '')};
@ -26,6 +26,12 @@ export const Text = (props: TextProps) => {
return <StyledDefaultText {...props}>{props.text}</StyledDefaultText>;
};
export const TextWithChildren = (
props: Omit<TextProps, 'text'> & { children: React.ReactNode }
) => {
return <StyledDefaultText {...props}>{props.children}</StyledDefaultText>;
};
type SpacerProps = {
size: 'xl' | 'lg' | 'md' | 'sm' | 'xs';
style?: CSSProperties;

View File

@ -17,7 +17,7 @@ import {
} from '../../state/selectors/selectedConversation';
import { ReleasedFeatures } from '../../util/releaseFeature';
import { Flex } from '../basic/Flex';
import { Text } from '../basic/Text';
import { TextWithChildren } from '../basic/Text';
import { ExpirableReadableMessage } from './message/message-item/ExpirableReadableMessage';
// eslint-disable-next-line import/order
import { pick } from 'lodash';
@ -25,6 +25,7 @@ import { ConversationInteraction } from '../../interactions';
import { getConversationController } from '../../session/conversations';
import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { SessionButtonColor } from '../basic/SessionButton';
import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
const FollowSettingButton = styled.button`
color: var(--primary-color);
@ -208,7 +209,9 @@ export const TimerNotification = (props: PropsForExpirationTimer) => {
padding="5px 10px"
style={{ textAlign: 'center' }}
>
<Text text={textToRender} subtle={true} />
<TextWithChildren subtle={true}>
<SessionHtmlRenderer html={textToRender} />
</TextWithChildren>
<FollowSettingsButton {...props} />
</Flex>
</ExpirableReadableMessage>

View File

@ -6,6 +6,7 @@ import { useMessageExpirationPropsById } from '../../../../hooks/useParamSelecto
import { useMessageStatus } from '../../../../state/selectors';
import { getMostRecentMessageId } from '../../../../state/selectors/conversations';
import { useSelectedIsGroup } from '../../../../state/selectors/selectedConversation';
import { SpacerXS } from '../../../basic/Text';
import { SessionIcon, SessionIconType } from '../../../icon';
import { ExpireTimer } from '../../ExpireTimer';
@ -60,7 +61,7 @@ export const MessageStatus = (props: Props) => {
}
};
const MessageStatusContainer = styled.div<{ isIncoming: boolean }>`
const MessageStatusContainer = styled.div<{ isIncoming: boolean; isGroup: boolean }>`
display: inline-block;
align-self: ${props => (props.isIncoming ? 'flex-start' : 'flex-end')};
flex-direction: ${props =>
@ -73,6 +74,8 @@ const MessageStatusContainer = styled.div<{ isIncoming: boolean }>`
cursor: pointer;
display: flex;
align-items: center;
margin-inline-start: ${props =>
props.isGroup || !props.isIncoming ? 'var(--width-avatar-group-msg-list)' : 0};
`;
const StyledStatusText = styled.div`
@ -144,7 +147,12 @@ function MessageStatusExpireTimer(props: Props) {
const MessageStatusSending = ({ dataTestId }: Props) => {
// while sending, we do not display the expire timer at all.
return (
<MessageStatusContainer data-testid={dataTestId} data-testtype="sending" isIncoming={false}>
<MessageStatusContainer
data-testid={dataTestId}
data-testtype="sending"
isIncoming={false}
isGroup={false}
>
<TextDetails text={window.i18n('sending')} />
<IconNormal rotateDuration={2} iconType="sending" />
</MessageStatusContainer>
@ -171,13 +179,19 @@ function IconForExpiringMessageId({
const MessageStatusSent = ({ dataTestId, messageId }: Props) => {
const isExpiring = useIsExpiring(messageId);
const isMostRecentMessage = useIsMostRecentMessage(messageId);
const isGroup = useSelectedIsGroup();
// we hide a "sent" message status which is not expiring except for the most recent message
if (!isExpiring && !isMostRecentMessage) {
return null;
}
return (
<MessageStatusContainer data-testid={dataTestId} data-testtype="sent" isIncoming={false}>
<MessageStatusContainer
data-testid={dataTestId}
data-testtype="sent"
isIncoming={false}
isGroup={isGroup}
>
<TextDetails text={window.i18n('sent')} />
<IconForExpiringMessageId messageId={messageId} iconType="circleCheck" />
</MessageStatusContainer>
@ -190,6 +204,7 @@ const MessageStatusRead = ({
isIncoming,
}: Props & { isIncoming: boolean }) => {
const isExpiring = useIsExpiring(messageId);
const isGroup = useSelectedIsGroup();
const isMostRecentMessage = useIsMostRecentMessage(messageId);
@ -199,7 +214,12 @@ const MessageStatusRead = ({
}
return (
<MessageStatusContainer data-testid={dataTestId} data-testtype="read" isIncoming={isIncoming}>
<MessageStatusContainer
data-testid={dataTestId}
data-testtype="read"
isIncoming={isIncoming}
isGroup={isGroup}
>
<TextDetails text={window.i18n('read')} />
<IconForExpiringMessageId messageId={messageId} iconType="doubleCheckCircleFilled" />
</MessageStatusContainer>
@ -211,6 +231,7 @@ const MessageStatusError = ({ dataTestId }: Props) => {
ipcRenderer.send('show-debug-log');
}, []);
// when on error, we do not display the expire timer at all.
const isGroup = useSelectedIsGroup();
return (
<MessageStatusContainer
@ -219,6 +240,7 @@ const MessageStatusError = ({ dataTestId }: Props) => {
onClick={showDebugLog}
title={window.i18n('sendFailed')}
isIncoming={false}
isGroup={isGroup}
>
<TextDetails text={window.i18n('failed')} />
<IconDanger iconType="error" />

View File

@ -252,6 +252,19 @@ async function saveMessages(arrayOfMessages: Array<MessageAttributes>): Promise<
await channels.saveMessages(cleanData(arrayOfMessages));
}
/**
*
* @param conversationId the conversation from which to remove all but the most recent disappear timer update
* @param isPrivate if that conversation is private, we keep a expiration timer update for each sender
* @returns the array of messageIds removed, or [] if none were removed
*/
async function cleanUpExpirationTimerUpdateHistory(
conversationId: string,
isPrivate: boolean
): Promise<Array<string>> {
return channels.cleanUpExpirationTimerUpdateHistory(conversationId, isPrivate);
}
async function removeMessage(id: string): Promise<void> {
const message = await getMessageById(id, true);
@ -800,6 +813,7 @@ export const Data = {
saveMessages,
removeMessage,
removeMessagesByIds,
cleanUpExpirationTimerUpdateHistory,
getMessageIdsFromServerIds,
getMessageById,
getMessagesBySenderAndSentAt,

View File

@ -41,6 +41,7 @@ const channelsToMake = new Set([
'saveMessages',
'removeMessage',
'removeMessagesByIds',
'cleanUpExpirationTimerUpdateHistory',
'getUnreadByConversation',
'getUnreadDisappearingByConversation',
'markAllAsReadByConversationNoExpiration',

View File

@ -48,6 +48,7 @@ import {
conversationsChanged,
markConversationFullyRead,
MessageModelPropsWithoutConvoProps,
messagesDeleted,
ReduxConversationType,
} from '../state/ducks/conversations';
@ -823,7 +824,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
fromSync, // if the update comes from a config or sync message
fromCurrentDevice,
shouldCommitConvo = true,
shouldCommitMessage = true,
existingMessage,
}: {
providedDisappearingMode?: DisappearingMessageConversationModeType;
@ -833,7 +833,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
fromSync: boolean;
fromCurrentDevice: boolean;
shouldCommitConvo?: boolean;
shouldCommitMessage?: boolean;
existingMessage?: MessageModel;
}): Promise<boolean> {
const isRemoteChange = Boolean((receivedAt || fromSync) && !fromCurrentDevice);
@ -864,7 +863,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
);
const isV2DisappearReleased = ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached();
// when the v2 disappear is released, the changes we make are only for our outgoing messages, not shared with a contact anymore
if (isV2DisappearReleased) {
if (!this.isPrivate()) {
@ -873,6 +871,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
expireTimer,
});
} else if (fromSync || fromCurrentDevice) {
if (expirationMode === 'legacy') {
// TODO legacy messages support will be removed in a future release
return false;
}
// v2 is live, this is a private chat and a change we made, set the setting to what was given, otherwise discard it
this.set({
expirationMode,
@ -960,16 +962,16 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
message.get('id')
),
});
if (shouldCommitMessage) {
await message.commit();
}
}
}
await message.commit();
await cleanUpExpireHistoryFromConvo(this.id, this.isPrivate());
return true;
}
if (shouldCommitMessage) {
await message.commit();
}
await message.commit();
await cleanUpExpireHistoryFromConvo(this.id, this.isPrivate());
//
// Below is the "sending the update to the conversation" part.
// We would have returned if that message sending part was not needed
@ -1158,18 +1160,18 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const sendReceipt =
settingsReadReceiptEnabled && !this.isBlocked() && !this.isIncomingRequest();
if (sendReceipt) {
window?.log?.info(`Sending ${timestamps.length} read receipts.`);
// we should probably stack read receipts and send them every 5 seconds for instance per conversation
const receiptMessage = new ReadReceiptMessage({
timestamp: Date.now(),
timestamps,
});
const device = new PubKey(this.id);
await getMessageQueue().sendToPubKey(device, receiptMessage, SnodeNamespaces.UserMessages);
if (!sendReceipt) {
return;
}
window?.log?.info(`Sending ${timestamps.length} read receipts.`);
const receiptMessage = new ReadReceiptMessage({
timestamp: Date.now(),
timestamps,
});
const device = new PubKey(this.id);
await getMessageQueue().sendToPubKey(device, receiptMessage, SnodeNamespaces.UserMessages);
}
public async setNickname(nickname: string | null, shouldCommit = false) {
@ -2519,3 +2521,14 @@ export function hasValidIncomingRequestValues({
const isActive = activeAt && isFinite(activeAt) && activeAt > 0;
return Boolean(isPrivate && !isMe && !isApproved && !isBlocked && isActive && didApproveMe);
}
async function cleanUpExpireHistoryFromConvo(conversationId: string, isPrivate: boolean) {
const updateIdsRemoved = await Data.cleanUpExpirationTimerUpdateHistory(
conversationId,
isPrivate
);
window.inboxStore.dispatch(
messagesDeleted(updateIdsRemoved.map(m => ({ conversationKey: conversationId, messageId: m })))
);
}

View File

@ -1677,6 +1677,8 @@ function updateToSessionSchemaVersion34(currentVersion: number, db: BetterSqlite
// Message changes
db.prepare(`ALTER TABLE ${MESSAGES_TABLE} ADD COLUMN expirationType TEXT;`).run();
db.prepare(`ALTER TABLE ${MESSAGES_TABLE} ADD COLUMN flags INTEGER;`).run();
db.prepare(`UPDATE ${MESSAGES_TABLE} SET flags = json_extract(json, '$.flags');`);
// #endregion

View File

@ -61,6 +61,8 @@ import {
} from '../types/sqlSharedTypes';
import { KNOWN_BLINDED_KEYS_ITEM, SettingsKey } from '../data/settings-key';
import { MessageAttributes } from '../models/messageType';
import { SignalService } from '../protobuf';
import { Quote } from '../receiver/types';
import {
getSQLCipherIntegrityCheck,
@ -780,11 +782,10 @@ function getMessageCount() {
return row['count(*)'];
}
function saveMessage(data: any) {
function saveMessage(data: MessageAttributes) {
const {
body,
conversationId,
// eslint-disable-next-line camelcase
expires_at,
hasAttachments,
hasFileAttachments,
@ -792,10 +793,8 @@ function saveMessage(data: any) {
id,
serverId,
serverTimestamp,
// eslint-disable-next-line camelcase
received_at,
sent,
// eslint-disable-next-line camelcase
sent_at,
source,
type,
@ -803,6 +802,7 @@ function saveMessage(data: any) {
expirationType,
expireTimer,
expirationStartTimestamp,
flags,
} = data;
if (!id) {
@ -834,6 +834,7 @@ function saveMessage(data: any) {
source,
type: type || '',
unread,
flags: flags ?? 0,
};
assertGlobalInstance()
@ -857,7 +858,8 @@ function saveMessage(data: any) {
sent_at,
source,
type,
unread
unread,
flags
) values (
$id,
$json,
@ -877,7 +879,8 @@ function saveMessage(data: any) {
$sent_at,
$source,
$type,
$unread
$unread,
$flags
);`
)
.run(payload);
@ -959,8 +962,8 @@ function cleanSeenMessages() {
});
}
function saveMessages(arrayOfMessages: Array<any>) {
console.info('saveMessages of length: ', arrayOfMessages.length);
function saveMessages(arrayOfMessages: Array<MessageAttributes>) {
console.info('saveMessages count: ', arrayOfMessages.length);
assertGlobalInstance().transaction(() => {
map(arrayOfMessages, saveMessage);
})();
@ -969,8 +972,6 @@ function saveMessages(arrayOfMessages: Array<any>) {
function removeMessage(id: string, instance?: BetterSqlite3.Database) {
if (!isString(id)) {
throw new Error('removeMessage: only takes single message to delete!');
return;
}
assertGlobalInstanceOrInstance(instance)
@ -1008,6 +1009,48 @@ function removeAllMessagesInConversation(
.run({ conversationId });
}
function cleanUpExpirationTimerUpdateHistory(
conversationId: string,
isPrivate: boolean,
db?: BetterSqlite3.Database
) {
if (isEmpty(conversationId)) {
return [];
}
const rows = assertGlobalInstanceOrInstance(db)
.prepare(
`SELECT id, source FROM ${MESSAGES_TABLE} WHERE conversationId = $conversationId and flags = ${SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE} ${orderByClause}`
)
.all({ conversationId });
if (rows.length <= 1) {
return [];
}
// we want to allow 1 message at most per sender for private chats only
const bySender: Record<string, Array<string>> = {};
// we keep the order, so the first message of each array should be kept, the other ones discarded
rows.forEach(r => {
const groupedById = isPrivate ? r.source : conversationId;
if (!bySender[groupedById]) {
bySender[groupedById] = [];
}
bySender[groupedById].push(r.id);
});
const allMsgIdsRemoved: Array<string> = [];
Object.keys(bySender).forEach(k => {
const idsToRemove = bySender[k].slice(1); // we keep the first one
if (isEmpty(idsToRemove)) {
return;
}
removeMessagesByIds(idsToRemove, db);
allMsgIdsRemoved.push(...idsToRemove);
});
return allMsgIdsRemoved;
}
function getMessageIdsFromServerIds(serverIds: Array<string | number>, conversationId: string) {
if (!Array.isArray(serverIds)) {
return [];
@ -2414,6 +2457,7 @@ export const sqlNode = {
saveMessages,
removeMessage,
removeMessagesByIds,
cleanUpExpirationTimerUpdateHistory,
removeAllMessagesInConversation,
getUnreadByConversation,
getUnreadDisappearingByConversation,

View File

@ -279,7 +279,6 @@ export async function handleNewClosedGroup(
const envelopeTimestamp = toNumber(envelope.timestamp);
// a type new is sent and received on one to one so do not use envelope.senderIdentity here
const sender = envelope.source;
if (
(await sentAtMoreRecentThanWrapper(envelopeTimestamp, 'UserGroupsConfig')) ===
'wrapper_more_recent'

View File

@ -230,6 +230,7 @@ async function handleUserProfileUpdate(result: IncomingConfResult): Promise<Inco
let changes = false;
const expireTimer = ourConvo.getExpireTimer();
const wrapperNoteToSelfExpirySeconds = await UserConfigWrapperActions.getNoteToSelfExpiry();
if (wrapperNoteToSelfExpirySeconds !== expireTimer) {

View File

@ -474,7 +474,6 @@ export async function innerHandleSwarmContentMessage(
content,
conversationModelForUIUpdate
);
// TODO legacy messages support will be removed in a future release
if (expireUpdate?.isDisappearingMessagesV2Released) {
await DisappearingMessages.checkHasOutdatedDisappearingMessageClient(

View File

@ -1,4 +1,4 @@
import { throttle, uniq } from 'lodash';
import { isNumber, throttle, uniq } from 'lodash';
import { messagesExpired } from '../../state/ducks/conversations';
import { initWallClockListener } from '../../util/wallClockListener';
@ -102,7 +102,7 @@ async function checkExpiringMessages() {
}
const expiresAt = next.getExpiresAt();
if (!expiresAt) {
if (!expiresAt || !isNumber(expiresAt)) {
return;
}
window.log.info('next message expires', new Date(expiresAt).toISOString());

View File

@ -1,5 +1,4 @@
// TODO legacy messages support will be removed in a future release
import { isNumber } from 'lodash';
import { ProtobufUtils, SignalService } from '../../protobuf';
import { ReleasedFeatures } from '../../util/releaseFeature';
import { DisappearingMessageConversationModeType } from './types';
@ -26,16 +25,10 @@ export function checkIsLegacyDisappearingDataMessage(
}
function contentHasTimerProp(contentMessage: SignalService.Content) {
return (
ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationTimer') ||
isNumber(contentMessage.expirationTimer)
);
return ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationTimer');
}
function contentHasTypeProp(contentMessage: SignalService.Content) {
return (
ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationType') ||
isNumber(contentMessage.expirationType)
);
return ProtobufUtils.hasDefinedProperty(contentMessage, 'expirationType');
}
/** Use this to check for legacy disappearing messages where the expirationType and expireTimer should be undefined on the ContentMessage */
@ -44,8 +37,8 @@ export function couldBeLegacyDisappearingMessageContent(
): boolean {
const couldBe =
(contentMessage.expirationType === SignalService.Content.ExpirationType.UNKNOWN ||
(ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached() &&
!contentHasTypeProp(contentMessage))) &&
ReleasedFeatures.isDisappearMessageV2FeatureReleasedCached()) &&
!contentHasTypeProp(contentMessage) &&
!contentHasTimerProp(contentMessage);
return couldBe;

View File

@ -148,10 +148,7 @@ async function send(
const storedAt = batchResult?.[0]?.body?.t;
const storedHash = batchResult?.[0]?.body?.hash;
// If message also has a sync message, save that hash. Otherwise save the hash from the regular message send i.e. only closed groups in this case.
if (
encryptedAndWrapped.identifier &&
(encryptedAndWrapped.isSyncMessage || isDestinationClosedGroup) &&
batchResult &&
!isEmpty(batchResult) &&
batchResult[0].code === 200 &&
@ -159,39 +156,48 @@ async function send(
isString(storedHash) &&
isNumber(storedAt)
) {
// TODO: the expiration is due to be returned by the storage server on "store" soon, we will then be able to use it instead of doing the storedAt + ttl logic below
// if we have a hash and a storedAt, mark it as seen so we don't reprocess it on the next retrieve
await Data.saveSeenMessageHashes([{ expiresAt: storedAt + ttl, hash: storedHash }]);
const foundMessage = await Data.getMessageById(encryptedAndWrapped.identifier);
if (foundMessage) {
await foundMessage.updateMessageHash(storedHash);
const convo = foundMessage.getConversation();
const expireTimer = foundMessage.getExpireTimer();
const expirationType = foundMessage.getExpirationType();
// If message also has a sync message, save that hash. Otherwise save the hash from the regular message send i.e. only closed groups in this case.
if (
convo &&
expirationType &&
expireTimer > 0 &&
// a message has started to disappear
foundMessage.getExpirationStartTimestamp()
) {
const expirationMode = DisappearingMessages.changeToDisappearingConversationMode(
convo,
expirationType,
expireTimer
);
if (
encryptedAndWrapped.identifier &&
(encryptedAndWrapped.isSyncMessage || isDestinationClosedGroup)
) {
const foundMessage = await Data.getMessageById(encryptedAndWrapped.identifier);
if (foundMessage) {
await foundMessage.updateMessageHash(storedHash);
const convo = foundMessage.getConversation();
const expireTimer = foundMessage.getExpireTimer();
const expirationType = foundMessage.getExpirationType();
const canBeDeleteAfterRead = convo && !convo.isMe() && convo.isPrivate();
// TODO legacy messages support will be removed in a future release
if (
canBeDeleteAfterRead &&
(expirationMode === 'legacy' || expirationMode === 'deleteAfterRead')
convo &&
expirationType &&
expireTimer > 0 &&
// a message has started to disappear
foundMessage.getExpirationStartTimestamp()
) {
await DisappearingMessages.updateMessageExpiryOnSwarm(foundMessage, 'send()');
}
}
const expirationMode = DisappearingMessages.changeToDisappearingConversationMode(
convo,
expirationType,
expireTimer
);
await foundMessage.commit();
const canBeDeleteAfterRead = convo && !convo.isMe() && convo.isPrivate();
// TODO legacy messages support will be removed in a future release
if (
canBeDeleteAfterRead &&
(expirationMode === 'legacy' || expirationMode === 'deleteAfterRead')
) {
await DisappearingMessages.updateMessageExpiryOnSwarm(foundMessage, 'send()');
}
}
await foundMessage.commit();
}
}
}

View File

@ -26,7 +26,6 @@ async function insertUserProfileIntoWrapper(convoId: string) {
const areBlindedMsgRequestEnabled = !!Storage.get(SettingsKey.hasBlindedMsgRequestsEnabled);
const expirySeconds = ourConvo.getExpireTimer() || 0;
window.log.debug(
`inserting into userprofile wrapper: username:"${dbName}", priority:${priority} image:${JSON.stringify(
{

View File

@ -600,7 +600,6 @@ describe('DisappearingMessage', () => {
receivedAt: GetNetworkTime.getNowWithNetworkOffset(),
fromSync: true,
shouldCommitConvo: false,
shouldCommitMessage: false,
existingMessage: undefined,
fromCurrentDevice: false,
});

View File

@ -1039,7 +1039,15 @@
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^17", "@types/react@^17.0.2":
"@types/react@*", "@types/react@17.0.2", "@types/react@^17":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/react@^17.0.2":
version "17.0.65"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.65.tgz#95f6a2ab61145ffb69129d07982d047f9e0870cd"
integrity sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ==
@ -1048,14 +1056,6 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/react@17.0.2":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/redux-logger@3.0.7":
version "3.0.7"
resolved "https://registry.yarnpkg.com/@types/redux-logger/-/redux-logger-3.0.7.tgz#163f6f6865c69c21d56f9356dc8d741718ec0db0"
@ -1817,9 +1817,9 @@ available-typed-arrays@^1.0.5:
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
axios@^1.3.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f"
integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==
version "1.6.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2"
integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
@ -4896,9 +4896,9 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
"libsession_util_nodejs@https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.0/libsession_util_nodejs-v0.3.0.tar.gz":
version "0.3.0"
resolved "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.0/libsession_util_nodejs-v0.3.0.tar.gz#83b733c8fdede577651881de239a8fd2843c929f"
"libsession_util_nodejs@https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.1/libsession_util_nodejs-v0.3.1.tar.gz":
version "0.3.1"
resolved "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.1/libsession_util_nodejs-v0.3.1.tar.gz#d2c94bfaae6e3ef594609abb08cf8be485fa5d39"
dependencies:
cmake-js "^7.2.1"
node-addon-api "^6.1.0"