You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
8.8 KiB
TypeScript
265 lines
8.8 KiB
TypeScript
import React, { useCallback, useState } from 'react';
|
|
import { useDispatch } from 'react-redux';
|
|
import { ed25519Str } from '../../session/onions/onionPath';
|
|
import { forceNetworkDeletion } from '../../session/apis/snode_api/SNodeAPI';
|
|
import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/syncUtils';
|
|
import { updateConfirmModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog';
|
|
import { SpacerLG } from '../basic/Text';
|
|
import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
|
|
import { SessionSpinner } from '../basic/SessionSpinner';
|
|
import { SessionWrapperModal } from '../SessionWrapperModal';
|
|
|
|
import { Data } from '../../data/data';
|
|
import { deleteAllLogs } from '../../node/logs';
|
|
import { SessionRadioGroup } from '../basic/SessionRadioGroup';
|
|
|
|
const deleteDbLocally = async () => {
|
|
window?.log?.info('last message sent successfully. Deleting everything');
|
|
window.persistStore?.purge();
|
|
await deleteAllLogs();
|
|
await Data.removeAll();
|
|
await Data.close();
|
|
await Data.removeDB();
|
|
await Data.removeOtherData();
|
|
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)
|
|
|
|
// send deletion message to the network
|
|
const potentiallyMaliciousSnodes = await 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();
|
|
},
|
|
})
|
|
);
|
|
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();
|
|
},
|
|
})
|
|
);
|
|
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;
|
|
|
|
const DescriptionBeforeAskingConfirmation = (props: {
|
|
deleteMode: DeleteModes;
|
|
setDeleteMode: (deleteMode: DeleteModes) => void;
|
|
}) => {
|
|
const { deleteMode, setDeleteMode } = props;
|
|
return (
|
|
<>
|
|
<span className="session-confirm-main-message">{window.i18n('deleteAccountWarning')}</span>
|
|
<span className="session-confirm-main-message">
|
|
{window.i18n('dialogClearAllDataDeletionQuestion')}
|
|
</span>
|
|
|
|
<SpacerLG />
|
|
<SessionRadioGroup
|
|
group="delete_account"
|
|
initialItem={deleteMode}
|
|
onClick={value => {
|
|
if (value === DEVICE_ONLY || value === DEVICE_AND_NETWORK) {
|
|
setDeleteMode(value);
|
|
}
|
|
}}
|
|
items={[
|
|
{ label: window.i18n('deviceOnly'), value: DEVICE_ONLY },
|
|
{ label: window.i18n('entireAccount'), value: 'device_and_network' },
|
|
]}
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const DescriptionWhenAskingConfirmation = (props: { deleteMode: DeleteModes }) => {
|
|
return (
|
|
<span className="session-confirm-main-message">
|
|
{props.deleteMode === 'device_and_network'
|
|
? window.i18n('areYouSureDeleteEntireAccount')
|
|
: window.i18n('areYouSureDeleteDeviceOnly')}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
export const DeleteAccountModal = () => {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [askingConfirmation, setAskingConfirmation] = useState(false);
|
|
const [deleteMode, setDeleteMode] = useState<DeleteModes>(DEVICE_ONLY);
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const onDeleteEverythingLocallyOnly = async () => {
|
|
if (!isLoading) {
|
|
setIsLoading(true);
|
|
try {
|
|
window.log.warn('Deleting everything on device but keeping network data');
|
|
|
|
await sendConfigMessageAndDeleteEverything();
|
|
} catch (e) {
|
|
window.log.warn(e);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}
|
|
};
|
|
const onDeleteEverythingAndNetworkData = async () => {
|
|
if (!isLoading) {
|
|
setIsLoading(true);
|
|
try {
|
|
window.log.warn('Deleting everything including network data');
|
|
await deleteEverythingAndNetworkData();
|
|
} catch (e) {
|
|
window.log.warn(e);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Performs specified on close action then removes the modal.
|
|
*/
|
|
const onClickCancelHandler = useCallback(() => {
|
|
dispatch(updateDeleteAccountModal(null));
|
|
}, []);
|
|
|
|
return (
|
|
<SessionWrapperModal
|
|
title={window.i18n('clearAllData')}
|
|
onClose={onClickCancelHandler}
|
|
showExitIcon={true}
|
|
>
|
|
{askingConfirmation ? (
|
|
<DescriptionWhenAskingConfirmation deleteMode={deleteMode} />
|
|
) : (
|
|
<DescriptionBeforeAskingConfirmation
|
|
deleteMode={deleteMode}
|
|
setDeleteMode={setDeleteMode}
|
|
/>
|
|
)}
|
|
<div className="session-modal__centered">
|
|
<div className="session-modal__button-group">
|
|
<SessionButton
|
|
text={window.i18n('clear')}
|
|
buttonColor={SessionButtonColor.Danger}
|
|
onClick={() => {
|
|
if (!askingConfirmation) {
|
|
setAskingConfirmation(true);
|
|
return;
|
|
}
|
|
if (deleteMode === 'device_only') {
|
|
void onDeleteEverythingLocallyOnly();
|
|
} else if (deleteMode === 'device_and_network') {
|
|
void onDeleteEverythingAndNetworkData();
|
|
}
|
|
}}
|
|
disabled={isLoading}
|
|
/>
|
|
|
|
<SessionButton
|
|
text={window.i18n('cancel')}
|
|
buttonColor={SessionButtonColor.Primary}
|
|
onClick={() => {
|
|
dispatch(updateDeleteAccountModal(null));
|
|
}}
|
|
disabled={isLoading}
|
|
/>
|
|
</div>
|
|
<SpacerLG />
|
|
|
|
<SessionSpinner loading={isLoading} />
|
|
</div>
|
|
</SessionWrapperModal>
|
|
);
|
|
};
|