feat: move db deletion methods to accountManager

pull/3083/head
William Grant 9 months ago
parent 490e4957f4
commit cebe7c884d

@ -1,171 +1,18 @@
import { useCallback, useState } from 'react';
import { useDispatch } from 'react-redux';
import { SnodeAPI } from '../../session/apis/snode_api/SNodeAPI';
import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/sync/syncUtils';
import { updateConfirmModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog';
import { updateDeleteAccountModal } from '../../state/ducks/modalDialog';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SpacerLG } from '../basic/Text';
import { SessionSpinner } from '../loading';
import { Data } from '../../data/data';
import { deleteAllLogs } from '../../node/logs';
import { clearInbox } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearInbox';
import { getAllValidOpenGroupV2ConversationRoomInfos } from '../../session/apis/open_group_api/utils/OpenGroupUtils';
import { ed25519Str } from '../../session/utils/String';
import {
deleteEverythingAndNetworkData,
sendConfigMessageAndDeleteEverything,
} from '../../util/accountManager';
import { SessionRadioGroup } from '../basic/SessionRadioGroup';
const deleteDbLocally = async () => {
window?.log?.info('last message sent successfully. Deleting everything');
await window.persistStore?.purge();
window?.log?.info('store purged');
await deleteAllLogs();
window?.log?.info('deleteAllLogs: done');
await Data.removeAll();
window?.log?.info('Data.removeAll: done');
await Data.close();
window?.log?.info('Data.close: done');
await Data.removeDB();
window?.log?.info('Data.removeDB: done');
await Data.removeOtherData();
window?.log?.info('Data.removeOtherData: done');
window.localStorage.setItem('restart-reason', 'delete-account');
};
async function sendConfigMessageAndDeleteEverything() {
try {
// DELETE LOCAL DATA ONLY, NOTHING ON NETWORK
window?.log?.info('DeleteAccount => Sending a last SyncConfiguration');
// be sure to wait for the message being effectively sent. Otherwise we won't be able to encrypt it for our devices !
await forceSyncConfigurationNowIfNeeded(true);
window?.log?.info('Last configuration message sent!');
await deleteDbLocally();
window.restart();
} catch (error) {
// if an error happened, it's not related to the delete everything on network logic as this is handled above.
// this could be a last sync configuration message not being sent.
// in all case, we delete everything, and restart
window?.log?.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await deleteDbLocally();
} catch (e) {
window?.log?.error(e);
} finally {
window.restart();
}
}
}
async function deleteEverythingAndNetworkData() {
try {
// DELETE EVERYTHING ON NETWORK, AND THEN STUFF LOCALLY STORED
// a bit of duplicate code below, but it's easier to follow every case like that (helped with returns)
// clear all sogs inboxes (includes message requests)
const allRoomInfos = await getAllValidOpenGroupV2ConversationRoomInfos();
if (allRoomInfos && allRoomInfos.size > 0) {
// clear each inbox per sogs
// eslint-disable-next-line no-restricted-syntax
for (const roomInfo of allRoomInfos.values()) {
try {
// eslint-disable-next-line no-await-in-loop
const success = await clearInbox(roomInfo);
if (!success) {
throw Error(`Failed to clear inbox for ${roomInfo.conversationId}`);
}
} catch (error) {
window.log.info('DeleteAccount =>', error);
continue;
}
}
}
// send deletion message to the network
const potentiallyMaliciousSnodes = await SnodeAPI.forceNetworkDeletion();
if (potentiallyMaliciousSnodes === null) {
window?.log?.warn('DeleteAccount => forceNetworkDeletion failed');
// close this dialog
window.inboxStore?.dispatch(updateDeleteAccountModal(null));
window.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
message: window.i18n('dialogClearAllDataDeletionFailedDesc'),
okTheme: SessionButtonColor.Danger,
okText: window.i18n('deviceOnly'),
onClickOk: async () => {
await deleteDbLocally();
window.restart();
},
onClickClose: () => {
window.inboxStore?.dispatch(updateConfirmModal(null));
},
})
);
return;
}
if (potentiallyMaliciousSnodes.length > 0) {
const snodeStr = potentiallyMaliciousSnodes.map(ed25519Str);
window?.log?.warn(
'DeleteAccount => forceNetworkDeletion Got some potentially malicious snodes',
snodeStr
);
// close this dialog
window.inboxStore?.dispatch(updateDeleteAccountModal(null));
// open a new confirm dialog to ask user what to do
window.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
message: window.i18n('dialogClearAllDataDeletionFailedMultiple', [
potentiallyMaliciousSnodes.join(', '),
]),
messageSub: window.i18n('dialogClearAllDataDeletionFailedTitleQuestion'),
okTheme: SessionButtonColor.Danger,
okText: window.i18n('deviceOnly'),
onClickOk: async () => {
await deleteDbLocally();
window.restart();
},
onClickClose: () => {
window.inboxStore?.dispatch(updateConfirmModal(null));
},
})
);
return;
}
// We removed everything on the network successfully (no malicious node!). Now delete the stuff we got locally
// without sending a last configuration message (otherwise this one will still be on the network)
await deleteDbLocally();
window.restart();
} catch (error) {
// if an error happened, it's not related to the delete everything on network logic as this is handled above.
// this could be a last sync configuration message not being sent.
// in all case, we delete everything, and restart
window?.log?.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await deleteDbLocally();
} catch (e) {
window?.log?.error(e);
}
window.restart();
}
}
const DEVICE_ONLY = 'device_only';
const DEVICE_AND_NETWORK = 'device_and_network';
type DeleteModes = typeof DEVICE_ONLY | typeof DEVICE_AND_NETWORK;

@ -1,16 +1,24 @@
import { isEmpty } from 'lodash';
import { getConversationController } from '../session/conversations';
import { getSodiumRenderer } from '../session/crypto';
import { fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String';
import { ed25519Str, fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String';
import { configurationMessageReceived, trigger } from '../shims/events';
import { SessionButtonColor } from '../components/basic/SessionButton';
import { Data } from '../data/data';
import { SettingsKey } from '../data/settings-key';
import { ConversationTypeEnum } from '../models/conversationAttributes';
import { deleteAllLogs } from '../node/logs';
import { SessionKeyPair } from '../receiver/keypairs';
import { clearInbox } from '../session/apis/open_group_api/sogsv3/sogsV3ClearInbox';
import { getAllValidOpenGroupV2ConversationRoomInfos } from '../session/apis/open_group_api/utils/OpenGroupUtils';
import { getSwarmPollingInstance } from '../session/apis/snode_api';
import { SnodeAPI } from '../session/apis/snode_api/SNodeAPI';
import { mnDecode, mnEncode } from '../session/crypto/mnemonic';
import { getOurPubKeyStrFromCache } from '../session/utils/User';
import { LibSessionUtil } from '../session/utils/libsession/libsession_utils';
import { forceSyncConfigurationNowIfNeeded } from '../session/utils/sync/syncUtils';
import { updateConfirmModal, updateDeleteAccountModal } from '../state/ducks/modalDialog';
import { actions as userActions } from '../state/ducks/user';
import { Registration } from './registration';
import { Storage, saveRecoveryPhrase, setLocalPubKey, setSignInByLinking } from './storage';
@ -236,3 +244,153 @@ export async function registrationDone(ourPubkey: string, displayName: string) {
// this will make the poller start fetching messages
trigger('registration_done');
}
const deleteDbLocally = async () => {
window?.log?.info('last message sent successfully. Deleting everything');
await window.persistStore?.purge();
window?.log?.info('store purged');
await deleteAllLogs();
window?.log?.info('deleteAllLogs: done');
await Data.removeAll();
window?.log?.info('Data.removeAll: done');
await Data.close();
window?.log?.info('Data.close: done');
await Data.removeDB();
window?.log?.info('Data.removeDB: done');
await Data.removeOtherData();
window?.log?.info('Data.removeOtherData: done');
window.localStorage.setItem('restart-reason', 'delete-account');
};
export async function sendConfigMessageAndDeleteEverything() {
try {
// DELETE LOCAL DATA ONLY, NOTHING ON NETWORK
window?.log?.info('DeleteAccount => Sending a last SyncConfiguration');
// be sure to wait for the message being effectively sent. Otherwise we won't be able to encrypt it for our devices !
await forceSyncConfigurationNowIfNeeded(true);
window?.log?.info('Last configuration message sent!');
await deleteDbLocally();
window.restart();
} catch (error) {
// if an error happened, it's not related to the delete everything on network logic as this is handled above.
// this could be a last sync configuration message not being sent.
// in all case, we delete everything, and restart
window?.log?.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await deleteDbLocally();
} catch (e) {
window?.log?.error(e);
} finally {
window.restart();
}
}
}
export async function deleteEverythingAndNetworkData() {
try {
// DELETE EVERYTHING ON NETWORK, AND THEN STUFF LOCALLY STORED
// a bit of duplicate code below, but it's easier to follow every case like that (helped with returns)
// clear all sogs inboxes (includes message requests)
const allRoomInfos = await getAllValidOpenGroupV2ConversationRoomInfos();
if (allRoomInfos && allRoomInfos.size > 0) {
// clear each inbox per sogs
// eslint-disable-next-line no-restricted-syntax
for (const roomInfo of allRoomInfos.values()) {
try {
// eslint-disable-next-line no-await-in-loop
const success = await clearInbox(roomInfo);
if (!success) {
throw Error(`Failed to clear inbox for ${roomInfo.conversationId}`);
}
} catch (error) {
window.log.info('DeleteAccount =>', error);
continue;
}
}
}
// send deletion message to the network
const potentiallyMaliciousSnodes = await SnodeAPI.forceNetworkDeletion();
if (potentiallyMaliciousSnodes === null) {
window?.log?.warn('DeleteAccount => forceNetworkDeletion failed');
// close this dialog
window?.inboxStore?.dispatch(updateDeleteAccountModal(null));
window?.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
message: window.i18n('dialogClearAllDataDeletionFailedDesc'),
okTheme: SessionButtonColor.Danger,
okText: window.i18n('deviceOnly'),
onClickOk: async () => {
await deleteDbLocally();
window.restart();
},
onClickClose: () => {
window.inboxStore?.dispatch(updateConfirmModal(null));
},
})
);
return;
}
if (potentiallyMaliciousSnodes.length > 0) {
const snodeStr = potentiallyMaliciousSnodes.map(ed25519Str);
window?.log?.warn(
'DeleteAccount => forceNetworkDeletion Got some potentially malicious snodes',
snodeStr
);
// close this dialog
window?.inboxStore?.dispatch(updateDeleteAccountModal(null));
// open a new confirm dialog to ask user what to do
window?.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
message: window.i18n('dialogClearAllDataDeletionFailedMultiple', [
potentiallyMaliciousSnodes.join(', '),
]),
messageSub: window.i18n('dialogClearAllDataDeletionFailedTitleQuestion'),
okTheme: SessionButtonColor.Danger,
okText: window.i18n('deviceOnly'),
onClickOk: async () => {
await deleteDbLocally();
window.restart();
},
onClickClose: () => {
window.inboxStore?.dispatch(updateConfirmModal(null));
},
})
);
return;
}
// We removed everything on the network successfully (no malicious node!). Now delete the stuff we got locally
// without sending a last configuration message (otherwise this one will still be on the network)
await deleteDbLocally();
window.restart();
} catch (error) {
// if an error happened, it's not related to the delete everything on network logic as this is handled above.
// this could be a last sync configuration message not being sent.
// in all case, we delete everything, and restart
window?.log?.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await deleteDbLocally();
} catch (e) {
window?.log?.error(e);
}
window.restart();
}
}

Loading…
Cancel
Save