move delete account logic to it's own dialog
							parent
							
								
									e43e9df8e0
								
							
						
					
					
						commit
						9991dc2364
					
				@ -0,0 +1,202 @@
 | 
			
		||||
import React, { useCallback, useState } from 'react';
 | 
			
		||||
import { ed25519Str } from '../../session/onions/onionPath';
 | 
			
		||||
import {
 | 
			
		||||
  forceNetworkDeletion,
 | 
			
		||||
  forceSyncConfigurationNowIfNeeded,
 | 
			
		||||
} from '../../session/utils/syncUtils';
 | 
			
		||||
import { updateConfirmModal, updateDeleteAccountModal } from '../../state/ducks/modalDialog';
 | 
			
		||||
import { SpacerLG } from '../basic/Text';
 | 
			
		||||
import { SessionButton, SessionButtonColor } from '../session/SessionButton';
 | 
			
		||||
import { SessionHtmlRenderer } from '../session/SessionHTMLRenderer';
 | 
			
		||||
import { SessionSpinner } from '../session/SessionSpinner';
 | 
			
		||||
import { SessionWrapperModal } from '../session/SessionWrapperModal';
 | 
			
		||||
 | 
			
		||||
const deleteDbLocally = async () => {
 | 
			
		||||
  window?.log?.info('configuration message sent successfully. Deleting everything');
 | 
			
		||||
  await window.Signal.Logs.deleteAll();
 | 
			
		||||
  await window.Signal.Data.removeAll();
 | 
			
		||||
  await window.Signal.Data.close();
 | 
			
		||||
  await window.Signal.Data.removeDB();
 | 
			
		||||
  await window.Signal.Data.removeOtherData();
 | 
			
		||||
  // 'unlink' => toast will be shown on app restart
 | 
			
		||||
  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');
 | 
			
		||||
 | 
			
		||||
      window.inboxStore?.dispatch(
 | 
			
		||||
        updateConfirmModal({
 | 
			
		||||
          title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
 | 
			
		||||
          message: window.i18n('dialogClearAllDataDeletionFailedDesc'),
 | 
			
		||||
          okTheme: SessionButtonColor.Danger,
 | 
			
		||||
          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
 | 
			
		||||
      );
 | 
			
		||||
      window.inboxStore?.dispatch(
 | 
			
		||||
        updateConfirmModal({
 | 
			
		||||
          title: window.i18n('dialogClearAllDataDeletionFailedTitle'),
 | 
			
		||||
          message: window.i18n('dialogClearAllDataDeletionFailedMultiple', snodeStr),
 | 
			
		||||
          okTheme: SessionButtonColor.Danger,
 | 
			
		||||
          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();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const DeleteAccountModal = () => {
 | 
			
		||||
  const [isLoading, setIsLoading] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const onDeleteEverythingLocallyOnly = async () => {
 | 
			
		||||
    setIsLoading(true);
 | 
			
		||||
    try {
 | 
			
		||||
      window.log.warn('Deleting everything excluding network data');
 | 
			
		||||
 | 
			
		||||
      await sendConfigMessageAndDeleteEverything();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      window.log.warn(e);
 | 
			
		||||
    } finally {
 | 
			
		||||
      setIsLoading(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dispatch(updateConfirmModal(null));
 | 
			
		||||
  };
 | 
			
		||||
  const onDeleteEverythingAndNetworkData = async () => {
 | 
			
		||||
    setIsLoading(true);
 | 
			
		||||
    try {
 | 
			
		||||
      window.log.warn('Deleting everything including network data');
 | 
			
		||||
      await deleteEverythingAndNetworkData();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      window.log.warn(e);
 | 
			
		||||
    } finally {
 | 
			
		||||
      setIsLoading(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dispatch(updateConfirmModal(null));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Performs specified on close action then removes the modal.
 | 
			
		||||
   */
 | 
			
		||||
  const onClickCancelHandler = useCallback(() => {
 | 
			
		||||
    window.inboxStore?.dispatch(updateDeleteAccountModal(null));
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SessionWrapperModal
 | 
			
		||||
      title={window.i18n('clearAllData')}
 | 
			
		||||
      onClose={onClickCancelHandler}
 | 
			
		||||
      showExitIcon={true}
 | 
			
		||||
    >
 | 
			
		||||
      <SpacerLG />
 | 
			
		||||
 | 
			
		||||
      <div className="session-modal__centered">
 | 
			
		||||
        <SessionHtmlRenderer
 | 
			
		||||
          tag="span"
 | 
			
		||||
          className="session-confirm-main-message"
 | 
			
		||||
          html={window.i18n('deleteAccountWarning')}
 | 
			
		||||
        />
 | 
			
		||||
        <SessionHtmlRenderer
 | 
			
		||||
          tag="span"
 | 
			
		||||
          className="session-confirm-main-message"
 | 
			
		||||
          html={window.i18n('dialogClearAllDataDeletionQuestion')}
 | 
			
		||||
        />
 | 
			
		||||
        <SpacerLG />
 | 
			
		||||
        <div className="session-modal__button-group">
 | 
			
		||||
          <SessionButton
 | 
			
		||||
            text={window.i18n('entireAccount')}
 | 
			
		||||
            buttonColor={SessionButtonColor.Danger}
 | 
			
		||||
            onClick={onDeleteEverythingAndNetworkData}
 | 
			
		||||
            disabled={isLoading}
 | 
			
		||||
          />
 | 
			
		||||
 | 
			
		||||
          <SessionButton
 | 
			
		||||
            text={window.i18n('deviceOnly')}
 | 
			
		||||
            buttonColor={SessionButtonColor.Danger}
 | 
			
		||||
            onClick={onDeleteEverythingLocallyOnly}
 | 
			
		||||
            disabled={isLoading}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <SessionSpinner loading={isLoading} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </SessionWrapperModal>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
function dispatch(arg0: {
 | 
			
		||||
  payload: import('../../state/ducks/modalDialog').ConfirmModalState;
 | 
			
		||||
  type: string;
 | 
			
		||||
}) {
 | 
			
		||||
  throw new Error('Function not implemented.');
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue