Merge branch 'pr_fixes' into disappearing_messages

pull/2660/head
William Grant 3 years ago
commit ecd4b53e84

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { getRightOverlayMode } from '../../../state/selectors/section'; import { getRightOverlayMode } from '../../../state/selectors/section';
@ -10,14 +10,9 @@ const ClosableOverlay = () => {
const rightOverlayMode = useSelector(getRightOverlayMode); const rightOverlayMode = useSelector(getRightOverlayMode);
const [showNewDisppearingMessageModes, setShowNewDisppearingMessageModes] = useState(false); const [showNewDisppearingMessageModes, setShowNewDisppearingMessageModes] = useState(false);
const checkForFeatureRelease = useCallback(async () => {
const isReleased = await checkIsFeatureReleased('Disappearing Messages V2');
return isReleased;
}, []);
useEffect(() => { useEffect(() => {
let isCancelled = false; let isCancelled = false;
checkForFeatureRelease() checkIsFeatureReleased('Disappearing Messages V2')
.then(result => { .then(result => {
if (isCancelled) { if (isCancelled) {
return; return;
@ -33,7 +28,7 @@ const ClosableOverlay = () => {
return () => { return () => {
isCancelled = true; isCancelled = true;
}; };
}, [checkForFeatureRelease]); }, []);
switch (rightOverlayMode) { switch (rightOverlayMode) {
case 'disappearing-messages': case 'disappearing-messages':

@ -13,11 +13,15 @@ import {
getSelectedConversationExpirationSettings, getSelectedConversationExpirationSettings,
getSelectedConversationKey, getSelectedConversationKey,
} from '../../../../../state/selectors/conversations'; } from '../../../../../state/selectors/conversations';
import { DEFAULT_TIMER_OPTION } from '../../../../../util/expiringMessages'; import {
DEFAULT_TIMER_OPTION,
DisappearingMessageConversationType,
} from '../../../../../util/expiringMessages';
import { useTimerOptionsByMode } from '../../../../../hooks/useParamSelector'; import { useTimerOptionsByMode } from '../../../../../hooks/useParamSelector';
import { Header } from './Header'; import { Header } from './Header';
import { DisappearingModes } from './DisappearingModes'; import { DisappearingModes } from './DisappearingModes';
import { TimeOptions } from './TimeOptions'; import { TimeOptions } from './TimeOptions';
import { getConversationController } from '../../../../../session/conversations';
const StyledScrollContainer = styled.div` const StyledScrollContainer = styled.div`
width: 100%; width: 100%;
@ -113,6 +117,21 @@ export const OverlayDisappearingMessages = (props: OverlayDisappearingMessagesPr
} }
}, [convoProps.expirationType, convoProps.expireTimer]); }, [convoProps.expirationType, convoProps.expireTimer]);
// TODO legacy messages support will be removed in a future
useEffect(() => {
if (unlockNewModes && modeSelected === 'legacy' && selectedConversationKey) {
const convo = getConversationController().get(selectedConversationKey);
if (convo) {
let defaultExpirationType: DisappearingMessageConversationType = 'deleteAfterRead';
if (convo.isMe() || convo.isMediumGroup()) {
defaultExpirationType = 'deleteAfterSend';
}
convo.set('expirationType', defaultExpirationType);
setModeSelected(defaultExpirationType);
}
}
}, [unlockNewModes, selectedConversationKey, modeSelected]);
return ( return (
<StyledScrollContainer> <StyledScrollContainer>
<StyledContainer container={true} flexDirection={'column'} alignItems={'center'}> <StyledContainer container={true} flexDirection={'column'} alignItems={'center'}>

@ -23,7 +23,7 @@ export const TimeOptions = (props: TimerOptionsProps) => {
<> <>
{!hasOnlyOneMode && <PanelLabel>{window.i18n('timer')}</PanelLabel>} {!hasOnlyOneMode && <PanelLabel>{window.i18n('timer')}</PanelLabel>}
<PanelButtonGroup> <PanelButtonGroup>
{options.map((option: any) => { {options.map(option => {
return ( return (
<PanelRadioButton <PanelRadioButton
key={option.name} key={option.name}

@ -65,7 +65,15 @@ async function deleteEverythingAndNetworkData() {
// clear each inbox per sogs // clear each inbox per sogs
for (const roomInfo of allRoomInfos.values()) { for (const roomInfo of allRoomInfos.values()) {
// TODO CONTINUE testing - use a dummy account with some message requests and then if we restore from seed there should be no message requests. // TODO CONTINUE testing - use a dummy account with some message requests and then if we restore from seed there should be no message requests.
await clearInbox(roomInfo); try {
const success = await clearInbox(roomInfo);
if (!success) {
throw Error(`Failed to clear inbox for ${roomInfo.conversationId}`);
}
} catch (error) {
window.log.info('DeleteAccount =>', error);
continue;
}
} }
} }

@ -184,7 +184,8 @@ export function useMessageReactsPropsById(messageId?: string) {
}); });
} }
// TODO remove 10 seconds timer // TODO use env variable to toggle test values?
// https://github.com/oxen-io/session-desktop/pull/2660/files#r1174823750
export function useTimerOptionsByMode(disappearingMessageMode?: string, hasOnlyOneMode?: boolean) { export function useTimerOptionsByMode(disappearingMessageMode?: string, hasOnlyOneMode?: boolean) {
return useSelector((state: StateType) => { return useSelector((state: StateType) => {
const options = state.timerOptions.timerOptions; const options = state.timerOptions.timerOptions;

@ -678,10 +678,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
expireTimer: chatMessageParams.expireTimer, expireTimer: chatMessageParams.expireTimer,
}); });
window.log.info( window.log.debug('sendMessageJob() closedGroupVisibleMessage', closedGroupVisibleMessage);
'WIP: sendMessageJob() closedGroupVisibleMessage',
closedGroupVisibleMessage
);
// we need the return await so that errors are caught in the catch {} // we need the return await so that errors are caught in the catch {}
await getMessageQueue().sendToGroup(closedGroupVisibleMessage); await getMessageQueue().sendToGroup(closedGroupVisibleMessage);
@ -1075,9 +1072,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
existingMessage?: MessageModel; existingMessage?: MessageModel;
}): Promise<void> { }): Promise<void> {
if (this.isPublic()) { if (this.isPublic()) {
window.log.warning( window.log.warn("updateExpireTimer() Disappearing messages aren't supported in communities");
"WIP: updateExpireTimer() Disappearing messages aren't supported in communities"
);
return; return;
} }
@ -1094,7 +1089,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if ( if (
this.get('lastDisappearingMessageChangeTimestamp') > lastDisappearingMessageChangeTimestamp this.get('lastDisappearingMessageChangeTimestamp') > lastDisappearingMessageChangeTimestamp
) { ) {
window.log.info('WIP: updateExpireTimer() This is an outdated disappearing message setting'); window.log.info('updateExpireTimer() This is an outdated disappearing message setting');
return; return;
} }
@ -1103,7 +1098,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
isEqual(expireTimer, this.get('expireTimer')) isEqual(expireTimer, this.get('expireTimer'))
) { ) {
window.log.info( window.log.info(
'WIP:updateExpireTimer() Dropping ExpireTimerUpdate message as we already have the same one set.' 'updateExpireTimer() Dropping ExpireTimerUpdate message as we already have the same one set.'
); );
return; return;
} }
@ -1126,7 +1121,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
lastDisappearingMessageChangeTimestamp, lastDisappearingMessageChangeTimestamp,
}); });
window?.log?.info('WIP: Updating conversation disappearing messages setting', { window?.log?.debug('Updating conversation disappearing messages setting', {
id: this.idForLogging(), id: this.idForLogging(),
expirationType, expirationType,
expireTimer, expireTimer,
@ -1197,7 +1192,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
// TODO Check that the args are correct // TODO Check that the args are correct
// This might be happening too late in the message pipeline. Maybe should be moved to handleExpirationTimerUpdateNoCommit() // This might be happening too late in the message pipeline. Maybe should be moved to handleExpirationTimerUpdateNoCommit()
if (expireUpdate.expirationType === 'deleteAfterRead') { if (expireUpdate.expirationType === 'deleteAfterRead') {
window.log.info('WIP: Note to Self messages cannot be delete after read!'); window.log.info('Note to Self messages cannot be delete after read!');
return; return;
} }

@ -1280,7 +1280,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
await this.commit(); await this.commit();
} }
window?.log?.info('WIP: Set message expiration', { window?.log?.debug('Set message expiration', {
expiresAt, expiresAt,
sentAt: this.get('sent_at'), sentAt: this.get('sent_at'),
}); });

@ -417,7 +417,7 @@ export async function innerHandleSwarmContentMessage(
expireUpdate expireUpdate
); );
if (expireUpdate.isLegacyConversationSettingMessage) { if (expireUpdate.isLegacyConversationSettingMessage) {
window.log.info('WIP: The legacy message is an expiration timer update. Ignoring it.'); window.log.info('The legacy message is an expiration timer update. Ignoring it.');
return; return;
} }
} }

@ -246,7 +246,7 @@ export async function handleSwarmDataMessage(
if (expireUpdate && !isEmpty(expireUpdate)) { if (expireUpdate && !isEmpty(expireUpdate)) {
if (isSyncedMessage) { if (isSyncedMessage) {
// TODO handle sync messages expiring separately? // TODO handle sync messages expiring separately?
window.log.info('WIP: Sync Message dropping'); window.log.debug('WIP: Sync Message dropping');
} else { } else {
msgModel = handleExpireUpdate(convoToAddMessageTo, msgModel, expireUpdate); msgModel = handleExpireUpdate(convoToAddMessageTo, msgModel, expireUpdate);
} }

@ -198,7 +198,7 @@ export type RegularMessageType = Pick<
| 'reaction' | 'reaction'
| 'profile' | 'profile'
| 'profileKey' | 'profileKey'
// TODO Will be removed 2 weeks after release // TODO legacy messages support will be removed in a future release
| 'expireTimer' | 'expireTimer'
> & { isRegularMessage: true }; > & { isRegularMessage: true };
@ -361,7 +361,7 @@ export async function handleMessageJob(
(!expirationTimerUpdate || isEmpty(expirationTimerUpdate)) (!expirationTimerUpdate || isEmpty(expirationTimerUpdate))
) { ) {
window.log.info( window.log.info(
'WIP: There is a problem with the expiration timer update', 'There is a problem with the expiration timer update',
messageModel, messageModel,
expirationTimerUpdate expirationTimerUpdate
); );
@ -380,7 +380,7 @@ export async function handleMessageJob(
) { ) {
confirm?.(); confirm?.();
window?.log?.info( window?.log?.info(
'WIP: Dropping ExpireTimerUpdate message as we already have the same one set.' 'Dropping ExpireTimerUpdate message as we already have the same one set.'
); );
return; return;
} }

@ -1,5 +1,4 @@
import AbortController from 'abort-controller'; import AbortController from 'abort-controller';
import { Data } from '../../../../data/data';
import { OpenGroupRequestCommonType } from '../opengroupV2/ApiUtil'; import { OpenGroupRequestCommonType } from '../opengroupV2/ApiUtil';
import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils'; import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils';
import { import {
@ -8,6 +7,7 @@ import {
OpenGroupBatchRow, OpenGroupBatchRow,
sogsBatchSend, sogsBatchSend,
} from './sogsV3BatchPoll'; } from './sogsV3BatchPoll';
import { getConversationController } from '../../../conversations';
type OpenGroupClearInboxResponse = { type OpenGroupClearInboxResponse = {
deleted: number; deleted: number;
@ -16,11 +16,11 @@ type OpenGroupClearInboxResponse = {
export const clearInbox = async (roomInfos: OpenGroupRequestCommonType): Promise<boolean> => { export const clearInbox = async (roomInfos: OpenGroupRequestCommonType): Promise<boolean> => {
let success = false; let success = false;
const converationId = getOpenGroupV2ConversationId(roomInfos.serverUrl, roomInfos.roomId); const conversationId = getOpenGroupV2ConversationId(roomInfos.serverUrl, roomInfos.roomId);
const conversation = await Data.getConversationById(converationId); const conversation = getConversationController().get(conversationId);
if (!conversation) { if (!conversation) {
window.log.warn('clearInbox Matching conversation not found in db'); throw new Error(`clearInbox Matching conversation not found in db ${conversationId}`);
} else { } else {
const options: Array<OpenGroupBatchRow> = [ const options: Array<OpenGroupBatchRow> = [
{ {
@ -40,27 +40,27 @@ export const clearInbox = async (roomInfos: OpenGroupRequestCommonType): Promise
); );
if (!result) { if (!result) {
throw new Error('Could not clearInbox, res is invalid'); throw new Error(`Could not clearInbox, res is invalid for ${conversationId}`);
} }
const rawMessage = const rawMessage =
(result.body && (result.body[0].body as OpenGroupClearInboxResponse)) || null; (result.body && (result.body[0].body as OpenGroupClearInboxResponse)) || null;
if (!rawMessage) { if (!rawMessage) {
throw new Error('clearInbox parsing failed'); throw new Error(`clearInbox parsing failed for ${conversationId}`);
} }
try { try {
if (batchGlobalIsSuccess(result) && batchFirstSubIsSuccess(result)) { if (batchGlobalIsSuccess(result) && batchFirstSubIsSuccess(result)) {
success = true; success = true;
window.log.info(`clearInbox ${rawMessage.deleted} messages deleted from ${converationId} `); window.log.info(`clearInbox ${rawMessage.deleted} messages deleted for ${conversationId} `);
} }
} catch (e) { } catch (e) {
window?.log?.error("clearInbox Can't decode JSON body"); window?.log?.error(`clearInbox Can't decode JSON body for ${conversationId}`);
} }
} }
if (!success) { if (!success) {
window.log.info(`clearInbox message deletion failed for ${converationId} `); window.log.info(`clearInbox message deletion failed for ${conversationId}`);
} }
return success; return success;
}; };

@ -554,8 +554,6 @@ export async function retrieveNextMessages(
handleTimestampOffset('retrieve', json.t); handleTimestampOffset('retrieve', json.t);
await handleHardforkResult(json); await handleHardforkResult(json);
// console.log(`WIP: retrieveNextMessages`, json.messages);
return json.messages || []; return json.messages || [];
} catch (e) { } catch (e) {
window?.log?.warn('exception while parsing json of nextMessage:', e); window?.log?.warn('exception while parsing json of nextMessage:', e);

@ -31,7 +31,7 @@ async function generateSignature({
// "expire" || ShortenOrExtend || expiry || messages[0] || ... || messages[N] // "expire" || ShortenOrExtend || expiry || messages[0] || ... || messages[N]
const verificationString = `expire${shortenOrExtend}${timestamp}${messageHashes.join('')}`; const verificationString = `expire${shortenOrExtend}${timestamp}${messageHashes.join('')}`;
const verificationData = StringUtils.encode(verificationString, 'utf8'); const verificationData = StringUtils.encode(verificationString, 'utf8');
// window.log.info(`WIP: generateSignature verificationString ${verificationString}`); window.log.debug(`generateSignature verificationString ${verificationString}`);
const message = new Uint8Array(verificationData); const message = new Uint8Array(verificationData);
const sodium = await getSodiumRenderer(); const sodium = await getSodiumRenderer();
@ -44,7 +44,7 @@ async function generateSignature({
pubkey_ed25519: pubkey_ed25519.pubKey, pubkey_ed25519: pubkey_ed25519.pubKey,
}; };
} catch (e) { } catch (e) {
window.log.warn('WIP: generateSignature failed with: ', e.message); window.log.warn('generateSignature failed with: ', e.message);
return null; return null;
} }
} }
@ -68,7 +68,7 @@ async function verifySignature({
unchangedHashes?: Record<string, string>; unchangedHashes?: Record<string, string>;
}): Promise<boolean> { }): Promise<boolean> {
if (!expiryApplied || isEmpty(messageHashes) || isEmpty(signature)) { if (!expiryApplied || isEmpty(messageHashes) || isEmpty(signature)) {
// window.log.info('WIP: WIP: verifySignature missing argument'); window.log.warn('verifySignature missing argument');
return false; return false;
} }
@ -91,7 +91,7 @@ async function verifySignature({
const verificationString = `${pubkey.key}${expiryApplied}${hashes.join('')}`; const verificationString = `${pubkey.key}${expiryApplied}${hashes.join('')}`;
const verificationData = StringUtils.encode(verificationString, 'utf8'); const verificationData = StringUtils.encode(verificationString, 'utf8');
// window.log.info(`WIP: verifySignature verificationString`, verificationString); window.log.debug('verifySignature verificationString', verificationString);
const sodium = await getSodiumRenderer(); const sodium = await getSodiumRenderer();
try { try {
@ -103,7 +103,7 @@ async function verifySignature({
return isValid; return isValid;
} catch (e) { } catch (e) {
window.log.warn('WIP: verifySignature failed with: ', e.message); window.log.warn('verifySignature failed with: ', e.message);
return false; return false;
} }
} }
@ -115,20 +115,19 @@ async function processExpirationResults(
messageHashes: Array<string> messageHashes: Array<string>
) { ) {
if (isEmpty(swarm)) { if (isEmpty(swarm)) {
throw Error(`WIP: expireOnNodes failed! ${messageHashes}`); throw Error(`expireOnNodes failed! ${messageHashes}`);
} }
// TODO need proper typing for swarm and results // TODO need proper typing for swarm and results
const results: Record<string, { hashes: Array<string>; expiry: number }> = {}; const results: Record<string, { hashes: Array<string>; expiry: number }> = {};
// window.log.info(`WIP: processExpirationResults start`, swarm, messageHashes); // window.log.debug(`processExpirationResults start`, swarm, messageHashes);
for (const nodeKey of Object.keys(swarm)) { for (const nodeKey of Object.keys(swarm)) {
// window.log.info(`WIP: processExpirationResults processing nodeKey`, nodeKey, swarm[nodeKey]);
if (!isEmpty(swarm[nodeKey].failed)) { if (!isEmpty(swarm[nodeKey].failed)) {
const reason = 'Unknown'; const reason = 'Unknown';
const statusCode = '404'; const statusCode = '404';
window?.log?.warn( window?.log?.warn(
`WIP: loki_message:::expireMessage - Couldn't delete data from: ${ `loki_message:::expireMessage - Couldn't delete data from: ${
targetNode.pubkey_ed25519 targetNode.pubkey_ed25519
}${reason && statusCode && ` due to an error ${reason} (${statusCode})`}` }${reason && statusCode && ` due to an error ${reason} (${statusCode})`}`
); );
@ -141,8 +140,6 @@ async function processExpirationResults(
const expiryApplied = swarm[nodeKey].expiry; const expiryApplied = swarm[nodeKey].expiry;
const signature = swarm[nodeKey].signature; const signature = swarm[nodeKey].signature;
// window.log.info(`WIP: processExpirationResults swarm[nodeKey]`, swarm[nodeKey]);
const isValid = await verifySignature({ const isValid = await verifySignature({
pubkey, pubkey,
snodePubkey: nodeKey, snodePubkey: nodeKey,
@ -155,7 +152,7 @@ async function processExpirationResults(
if (!isValid) { if (!isValid) {
window.log.warn( window.log.warn(
'WIP: loki_message:::expireMessage - Signature verification failed!', 'loki_message:::expireMessage - Signature verification failed!',
messageHashes messageHashes
); );
} }
@ -189,27 +186,21 @@ async function expireOnNodes(targetNode: Snode, params: ExpireParams) {
try { try {
const parsed = JSON.parse(result.body); const parsed = JSON.parse(result.body);
await processExpirationResults(params.pubkey, targetNode, parsed.swarm, params.messages); const expirationResults = await processExpirationResults(
params.pubkey,
// const expirationResults = await processExpirationResults( targetNode,
// params.pubkey, parsed.swarm,
// targetNode, params.messages
// parsed.swarm, );
// params.messages window.log.debug('expireOnNodes attempt complete. Here are the results', expirationResults);
// );
// window.log.info(`WIP: expireOnNodes attempt complete. Here are the results`, expirationResults);
return true; return true;
} catch (e) { } catch (e) {
window?.log?.warn('WIP: Failed to parse "swarm" result: ', e.msg); window?.log?.warn('expireOnNodes Failed to parse "swarm" result: ', e.msg);
} }
return false; return false;
} catch (e) { } catch (e) {
window?.log?.warn( window?.log?.warn('expire - send error:', e, `destination ${targetNode.ip}:${targetNode.port}`);
'WIP: expire - send error:',
e,
`destination ${targetNode.ip}:${targetNode.port}`
);
throw e; throw e;
} }
} }
@ -223,7 +214,6 @@ type ExpireMessageOnSnodeProps = {
export async function expireMessageOnSnode(props: ExpireMessageOnSnodeProps) { export async function expireMessageOnSnode(props: ExpireMessageOnSnodeProps) {
const { messageHash, expireTimer, extend, shorten } = props; const { messageHash, expireTimer, extend, shorten } = props;
// window.log.info('WIP: expireMessageOnSnode running!');
if (extend && shorten) { if (extend && shorten) {
window.log.error( window.log.error(
@ -270,8 +260,6 @@ export async function expireMessageOnSnode(props: ExpireMessageOnSnodeProps) {
signature: signResult?.signature, signature: signResult?.signature,
}; };
// window.log.info(`WIP: expireMessageOnSnode params`, params);
const usedNodes = slice(swarm, 0, DEFAULT_CONNECTIONS); const usedNodes = slice(swarm, 0, DEFAULT_CONNECTIONS);
if (!usedNodes || usedNodes.length === 0) { if (!usedNodes || usedNodes.length === 0) {
throw new EmptySwarmError(ourPubKey.key, 'Ran out of swarm nodes to query'); throw new EmptySwarmError(ourPubKey.key, 'Ran out of swarm nodes to query');
@ -289,7 +277,6 @@ export async function expireMessageOnSnode(props: ExpireMessageOnSnodeProps) {
try { try {
const firstSuccessSnode = await firstTrue(promises); const firstSuccessSnode = await firstTrue(promises);
snode = firstSuccessSnode; snode = firstSuccessSnode;
// window.log.info(`WIP: expireMessageOnSnode firstSuccessSnode`, firstSuccessSnode);
} catch (e) { } catch (e) {
const snodeStr = snode ? `${snode.ip}:${snode.port}` : 'null'; const snodeStr = snode ? `${snode.ip}:${snode.port}` : 'null';
window?.log?.warn( window?.log?.warn(

@ -360,8 +360,7 @@ export class SwarmPolling {
const newMessages = messages.filter((m: Message) => !dupHashes.includes(m.hash)); const newMessages = messages.filter((m: Message) => !dupHashes.includes(m.hash));
if (newMessages.length) { if (newMessages.length) {
// TODO explain this better // NOTE setting expiresAt will trigger the global function destroyExpiredMessages() on it's next interval
// NOTE setting expiresAt here will trigger disappearing messages via the listener
const newHashes = newMessages.map((m: Message) => ({ const newHashes = newMessages.map((m: Message) => ({
expiresAt: m.expiration, expiresAt: m.expiration,
hash: m.hash, hash: m.hash,

@ -291,7 +291,7 @@ export async function updateOrCreateClosedGroup(details: GroupInfo) {
} }
await conversation.updateExpireTimer({ await conversation.updateExpireTimer({
// TODO clean up 2 weeks after release? // TODO legacy messages support will be removed in a future release
// TODO What are we cleaning? // TODO What are we cleaning?
providedExpirationType: expirationType || 'deleteAfterSend', providedExpirationType: expirationType || 'deleteAfterSend',
providedExpireTimer: expireTimer, providedExpireTimer: expireTimer,

@ -33,7 +33,6 @@ export class ExpirableMessage extends ContentMessage {
: this.expirationType === 'legacy' : this.expirationType === 'legacy'
? SignalService.Content.ExpirationType.UNKNOWN ? SignalService.Content.ExpirationType.UNKNOWN
: undefined, : undefined,
// TODO could use isFinite?
expirationTimer: this.expireTimer && this.expireTimer > -1 ? this.expireTimer : undefined, expirationTimer: this.expireTimer && this.expireTimer > -1 ? this.expireTimer : undefined,
}); });
} }

@ -8,8 +8,8 @@ import {
} from '../controlMessage/group/ClosedGroupMessage'; } from '../controlMessage/group/ClosedGroupMessage';
interface ClosedGroupVisibleMessageParams extends ClosedGroupMessageParams { interface ClosedGroupVisibleMessageParams extends ClosedGroupMessageParams {
// TODO Do we need strings? // TODO Refactor closed groups typings so groupId is PubKey only
// groupId: string | PubKey; // groupId: PubKey;
chatMessage: VisibleMessage; chatMessage: VisibleMessage;
} }

@ -41,7 +41,7 @@ async function handlePublicMessageSentSuccess(
} }
} }
// tslint:disable-next-line:// tslint:disable-next-line: cyclomatic-complexity // tslint:disable-next-line: cyclomatic-complexity
async function handleMessageSentSuccess( async function handleMessageSentSuccess(
sentMessage: RawMessage, sentMessage: RawMessage,
effectiveTimestamp: number, effectiveTimestamp: number,

@ -349,7 +349,7 @@ export const buildSyncMessage = (
if (expireUpdate && !isEmpty(expireUpdate)) { if (expireUpdate && !isEmpty(expireUpdate)) {
return buildSyncExpireTimerMessage(identifier, expireUpdate, timestamp, syncTarget); return buildSyncExpireTimerMessage(identifier, expireUpdate, timestamp, syncTarget);
} else { } else {
window.log.info('WIP: Building Sync Expire Timer Message failed', dataMessage, expireUpdate); window.log.warn('Building Sync Expire Timer Message failed', dataMessage, expireUpdate);
} }
} }
return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget); return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget);

@ -23,11 +23,11 @@ import {
export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call'; export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call';
export interface PropsForCallNotification extends PropsForExpiringMessage { export type PropsForCallNotification = PropsForExpiringMessage & {
notificationType: CallNotificationType; notificationType: CallNotificationType;
receivedAt: number; receivedAt: number;
isUnread: boolean; isUnread: boolean;
} };
export type MessageModelPropsWithoutConvoProps = { export type MessageModelPropsWithoutConvoProps = {
propsForMessage: PropsForMessageWithoutConvoProps; propsForMessage: PropsForMessageWithoutConvoProps;
@ -84,7 +84,7 @@ export type PropsForExpiringMessage = {
isExpired?: boolean; isExpired?: boolean;
}; };
export interface PropsForExpirationTimer extends PropsForExpiringMessage { export type PropsForExpirationTimer = PropsForExpiringMessage & {
expirationType: DisappearingMessageConversationType; expirationType: DisappearingMessageConversationType;
timespan: string; timespan: string;
disabled: boolean; disabled: boolean;
@ -97,7 +97,7 @@ export interface PropsForExpirationTimer extends PropsForExpiringMessage {
messageId: string; messageId: string;
isUnread: boolean; isUnread: boolean;
receivedAt: number | undefined; receivedAt: number | undefined;
} };
export type PropsForGroupUpdateGeneral = { export type PropsForGroupUpdateGeneral = {
type: 'general'; type: 'general';
@ -130,21 +130,21 @@ export type PropsForGroupUpdateType =
| PropsForGroupUpdateName | PropsForGroupUpdateName
| PropsForGroupUpdateLeft; | PropsForGroupUpdateLeft;
export interface PropsForGroupUpdate extends PropsForExpiringMessage { export type PropsForGroupUpdate = PropsForExpiringMessage & {
change: PropsForGroupUpdateType; change: PropsForGroupUpdateType;
messageId: string; messageId: string;
receivedAt: number | undefined; receivedAt: number | undefined;
isUnread: boolean; isUnread: boolean;
} };
export interface PropsForGroupInvitation extends PropsForExpiringMessage { export type PropsForGroupInvitation = PropsForExpiringMessage & {
serverName: string; serverName: string;
url: string; url: string;
acceptUrl: string; acceptUrl: string;
messageId: string; messageId: string;
receivedAt?: number; receivedAt?: number;
isUnread: boolean; isUnread: boolean;
} };
export type PropsForAttachment = { export type PropsForAttachment = {
id: number; id: number;

@ -10,6 +10,7 @@ import {
autoOrientJPEGAttachment, autoOrientJPEGAttachment,
captureDimensionsAndScreenshot, captureDimensionsAndScreenshot,
deleteData, deleteData,
deleteDataSuccessful,
loadData, loadData,
replaceUnicodeV2, replaceUnicodeV2,
} from './attachments/migrations'; } from './attachments/migrations';
@ -30,14 +31,14 @@ export const deleteExternalMessageFiles = async (message: {
await Promise.all(attachments.map(deleteData)); await Promise.all(attachments.map(deleteData));
// test that the files were deleted successfully // test that the files were deleted successfully
try { try {
await Promise.all( let results = await Promise.allSettled(attachments.map(deleteDataSuccessful));
attachments.map(async (attachment: { path: string; thumbnail: any; screenshot: any }) => { results = results.filter(result => result.status === 'rejected');
await readAttachmentData(attachment.path);
}) if (results.length) {
); throw Error;
window.log.info('[deleteExternalMessageFiles]: Failed to delete attachments for', message); }
} catch (err) { } catch (err) {
// If we fail to read the path then we know we deleted successfully window.log.warn('[deleteExternalMessageFiles]: Failed to delete attachments for', message);
} }
} }

@ -2,6 +2,7 @@ import * as GoogleChrome from '../../../ts/util/GoogleChrome';
import * as MIME from '../../../ts/types/MIME'; import * as MIME from '../../../ts/types/MIME';
import { toLogFormat } from './Errors'; import { toLogFormat } from './Errors';
import { arrayBufferToBlob, blobToArrayBuffer } from 'blob-util'; import { arrayBufferToBlob, blobToArrayBuffer } from 'blob-util';
import fse from 'fs-extra';
import { isString } from 'lodash'; import { isString } from 'lodash';
import { import {
@ -170,6 +171,27 @@ export const deleteData = async (attachment: { path: string; thumbnail: any; scr
return attachment; return attachment;
}; };
export const deleteDataSuccessful = async (attachment: {
path: string;
thumbnail: any;
screenshot: any;
}) => {
const errorMessage = `deleteDataSuccessful: Deletion failed for attachment ${attachment.path}`;
return fse.pathExists(attachment.path, (err, exists) => {
if (err) {
return Promise.reject(`${errorMessage} ${err}`);
}
// Note we want to confirm the path no longer exists
if (exists) {
return Promise.reject(errorMessage);
}
window.log.debug(`deleteDataSuccessful: Deletion succeeded for attachment ${attachment.path}`);
return true;
});
};
type CaptureDimensionType = { contentType: string; path: string }; type CaptureDimensionType = { contentType: string; path: string };
export const captureDimensionsAndScreenshot = async ( export const captureDimensionsAndScreenshot = async (

@ -235,8 +235,8 @@ export function setExpirationStartTimestamp(
// TODO legacy messages support will be removed in a future release // TODO legacy messages support will be removed in a future release
if (timestamp) { if (timestamp) {
window.log.info( window.log.debug(
`WIP: We compare 2 timestamps for a disappear ${ `We compare 2 timestamps for a disappear ${
isLegacyMode ? 'legacy' : mode === 'deleteAfterRead' ? 'after read' : 'after send' isLegacyMode ? 'legacy' : mode === 'deleteAfterRead' ? 'after read' : 'after send'
} message: \expirationStartTimestamp `, } message: \expirationStartTimestamp `,
new Date(expirationStartTimestamp).toLocaleTimeString(), new Date(expirationStartTimestamp).toLocaleTimeString(),
@ -248,22 +248,22 @@ export function setExpirationStartTimestamp(
// TODO legacy messages support will be removed in a future release // TODO legacy messages support will be removed in a future release
if (mode === 'deleteAfterRead') { if (mode === 'deleteAfterRead') {
window.log.info( window.log.debug(
`WIP: We set the start timestamp for a ${ `We set the start timestamp for a ${
isLegacyMode ? 'legacy ' : '' isLegacyMode ? 'legacy ' : ''
}delete after read message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}` }delete after read message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}`
); );
} else if (mode === 'deleteAfterSend') { } else if (mode === 'deleteAfterSend') {
window.log.info( window.log.debug(
`WIP: We set the start timestamp for a ${ `We set the start timestamp for a ${
isLegacyMode ? 'legacy ' : '' isLegacyMode ? 'legacy ' : ''
}delete after send message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}` }delete after send message to ${new Date(expirationStartTimestamp).toLocaleTimeString()}`
); );
} else if (mode === 'off') { } else if (mode === 'off') {
window.log.info(`WIP: Disappearing message mode "${mode}" set. We can safely ignore this.`); window.log.debug(`Disappearing message mode "${mode}" set. We can safely ignore this.`);
expirationStartTimestamp = undefined; expirationStartTimestamp = undefined;
} else { } else {
window.log.info(`WIP: Invalid disappearing message mode "${mode}" set. Ignoring`); window.log.debug(`Invalid disappearing message mode "${mode}" set. Ignoring`);
expirationStartTimestamp = undefined; expirationStartTimestamp = undefined;
} }
@ -332,7 +332,7 @@ export async function checkForExpireUpdate(
isDisappearingMessagesV2Released && isDisappearingMessagesV2Released &&
(isLegacyDataMessage || isLegacyConversationSettingMessage || shouldDisappearButIsntMessage) (isLegacyDataMessage || isLegacyConversationSettingMessage || shouldDisappearButIsntMessage)
) { ) {
window.log.info('WIP: received a legacy disappearing message after v2 was released.'); window.log.warn('Received a legacy disappearing message after v2 was released.', content);
expirationType = convoToUpdate.get('expirationType'); expirationType = convoToUpdate.get('expirationType');
expirationTimer = convoToUpdate.get('expireTimer'); expirationTimer = convoToUpdate.get('expireTimer');
} }
@ -346,8 +346,6 @@ export async function checkForExpireUpdate(
isDisappearingMessagesV2Released, isDisappearingMessagesV2Released,
}; };
// window.log.info('WIP: checkForExpireUpdate', expireUpdate);
return expireUpdate; return expireUpdate;
} }
@ -358,9 +356,7 @@ export function handleExpireUpdate(
expireUpdate: DisappearingMessageUpdate expireUpdate: DisappearingMessageUpdate
) { ) {
if (converationModel.isPublic()) { if (converationModel.isPublic()) {
window.log.warning( window.log.warn("updateExpireTimer() Disappearing messages aren't supported in communities");
"WIP: updateExpireTimer() Disappearing messages aren't supported in communities"
);
return messageModel; return messageModel;
} }

@ -1,4 +1,4 @@
import { Data } from '../data/data'; import { Storage } from './storage';
// TODO update to agreed value between platforms // TODO update to agreed value between platforms
const featureReleaseTimestamp = 1706778000000; // unix 01/02/2024 09:00 const featureReleaseTimestamp = 1706778000000; // unix 01/02/2024 09:00
@ -15,10 +15,10 @@ export function resetFeatureReleasedCachedValue() {
export async function getIsFeatureReleased(): Promise<boolean> { export async function getIsFeatureReleased(): Promise<boolean> {
if (isFeatureReleased === undefined) { if (isFeatureReleased === undefined) {
// read values from db and cache them as it looks like we did not // read values from db and cache them as it looks like we did not
const oldIsFeatureReleased = (await Data.getItemById('featureReleased'))?.value; const oldIsFeatureReleased = Boolean(Storage.get('featureReleased'));
// values do not exist in the db yet. Let's store false for now in the db and update our cached value. // values do not exist in the db yet. Let's store false for now in the db and update our cached value.
if (oldIsFeatureReleased === undefined) { if (oldIsFeatureReleased === undefined) {
await Data.createOrUpdateItem({ id: 'featureReleased', value: false }); await Storage.put('featureReleased', false);
isFeatureReleased = false; isFeatureReleased = false;
} else { } else {
isFeatureReleased = oldIsFeatureReleased; isFeatureReleased = oldIsFeatureReleased;
@ -36,30 +36,22 @@ export async function checkIsFeatureReleased(featureName: string): Promise<boole
if (featureAlreadyReleased) { if (featureAlreadyReleased) {
// Feature is already released and we don't need to update the db // Feature is already released and we don't need to update the db
} else { } else {
window.log.info( window.log.info(`[releaseFeature]: It is time to release ${featureName}. Releasing it now`);
`WIP: [releaseFeature]: It is time to release ${featureName}. Releasing it now` await Storage.put('featureReleased', true);
);
await Data.createOrUpdateItem({
id: 'featureReleased',
value: true,
});
} }
isFeatureReleased = true; isFeatureReleased = true;
} else { } else {
// Reset featureReleased to false if we have already released a feature since we have updated the featureReleaseTimestamp to a later date. // Reset featureReleased to false if we have already released a feature since we have updated the featureReleaseTimestamp to a later date.
// The alternative solution would be to do a db migration everytime we want to use this system. // The alternative solution would be to do a db migration everytime we want to use this system.
if (featureAlreadyReleased) { if (featureAlreadyReleased) {
await Data.createOrUpdateItem({ await Storage.put('featureReleased', false);
id: 'featureReleased',
value: false,
});
isFeatureReleased = false; isFeatureReleased = false;
} }
} }
} }
window.log.info( window.log.info(
`WIP: [releaseFeature]: ${featureName} ${ `[releaseFeature]: ${featureName} ${
Boolean(isFeatureReleased) ? 'is released' : 'has not been released yet' Boolean(isFeatureReleased) ? 'is released' : 'has not been released yet'
}` }`
); );

Loading…
Cancel
Save