diff --git a/preload.js b/preload.js index 4c250c3b9..71b1f1e4d 100644 --- a/preload.js +++ b/preload.js @@ -491,37 +491,3 @@ const { } = require('./ts/util/blockedNumberController'); window.BlockedNumberController = BlockedNumberController; -window.deleteAccount = async reason => { - const deleteEverything = 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', reason); - }; - try { - 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 window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded( - true - ); - window.log.info('Last configuration message sent!'); - await deleteEverything(); - } catch (error) { - window.log.error( - 'Something went wrong deleting all data:', - error && error.stack ? error.stack : error - ); - try { - await deleteEverything(); - } catch (e) { - window.log.error(e); - } - } - window.restart(); -}; diff --git a/ts/components/session/LeftPaneSettingSection.tsx b/ts/components/session/LeftPaneSettingSection.tsx index 352738fa2..241e41921 100644 --- a/ts/components/session/LeftPaneSettingSection.tsx +++ b/ts/components/session/LeftPaneSettingSection.tsx @@ -14,6 +14,7 @@ import { SessionSearchInput } from './SessionSearchInput'; import { SessionSettingCategory } from './settings/SessionSettings'; import { DefaultTheme } from 'styled-components'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; +import { AccountManager } from '../../util'; interface Props { settingsCategory: SessionSettingCategory; @@ -179,7 +180,7 @@ export class LeftPaneSettingSection extends React.Component { title, message, messageSub, - resolve: window.deleteAccount, + resolve: AccountManager.deleteAccount, okTheme: 'danger', }); } diff --git a/ts/components/session/SessionIDResetDialog.tsx b/ts/components/session/SessionIDResetDialog.tsx index d19439d8a..fe2c658db 100644 --- a/ts/components/session/SessionIDResetDialog.tsx +++ b/ts/components/session/SessionIDResetDialog.tsx @@ -4,6 +4,7 @@ import { SessionModal } from './SessionModal'; import { SessionButton, SessionButtonColor } from './SessionButton'; import { DefaultTheme, withTheme } from 'styled-components'; import { SessionIcon, SessionIconSize, SessionIconType } from './icon'; +import { AccountManager } from '../../util'; type Props = { onClose: any; @@ -40,7 +41,7 @@ const SessionIDResetDialogInner = (props: Props) => { { - window.deleteAccount('Session ID Upgrade'); + void AccountManager.deleteAccount('Session ID Upgrade'); props.onClose(); }} buttonColor={SessionButtonColor.Danger} diff --git a/ts/components/session/registration/RegistrationTabs.tsx b/ts/components/session/registration/RegistrationTabs.tsx index 935fcee15..95013f6d3 100644 --- a/ts/components/session/registration/RegistrationTabs.tsx +++ b/ts/components/session/registration/RegistrationTabs.tsx @@ -18,6 +18,7 @@ import { sessionGenerateKeyPair, } from '../../../util/accountManager'; import { fromHex, fromHexToArray } from '../../../session/utils/String'; +import { TaskTimedOutError } from '../../../session/utils/Promise'; export const MAX_USERNAME_LENGTH = 20; // tslint:disable: use-simple-attributes @@ -251,10 +252,17 @@ export async function signInWithLinking(signInDetails: { trigger('openInbox'); } catch (e) { await resetRegistration(); - ToastUtils.pushToastError( - 'registrationError', - `Error: ${e.message || 'Something went wrong'}` - ); + if (e instanceof TaskTimedOutError) { + ToastUtils.pushToastError( + 'registrationError', + 'Could not find your display name. Please Sign In by Restoring Your Account instead.' + ); + } else { + ToastUtils.pushToastError( + 'registrationError', + `Error: ${e.message || 'Something went wrong'}` + ); + } window.log.warn('exception during registration:', e); } } diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts index 06164fa60..e89c2712a 100644 --- a/ts/receiver/configMessage.ts +++ b/ts/receiver/configMessage.ts @@ -56,7 +56,7 @@ async function handleGroupsAndContactsFromConfigMessage( (await getItemById(hasSyncedInitialConfigurationItem))?.value || false; if (didWeHandleAConfigurationMessageAlready) { window?.log?.warn( - 'Dropping configuration change as we already handled one... ' + 'Dropping configuration contacts/groups change as we already handled one... ' ); return; } diff --git a/ts/session/utils/Promise.ts b/ts/session/utils/Promise.ts index 506d0ef51..deefd8796 100644 --- a/ts/session/utils/Promise.ts +++ b/ts/session/utils/Promise.ts @@ -5,6 +5,14 @@ async function toPromise(value: Return): Promise { return value instanceof Promise ? value : Promise.resolve(value); } +export class TaskTimedOutError extends Error { + constructor() { + super('Task timed out'); + // Set the prototype explicitly. + Object.setPrototypeOf(this, TaskTimedOutError.prototype); + } +} + /** * Create a promise which waits until `done` is called or until `timeout` period is reached. * If `timeout` is reached then this will throw an Error. @@ -19,7 +27,7 @@ export async function waitForTask( const timeoutPromise = new Promise((_, rej) => { const wait = setTimeout(() => { clearTimeout(wait); - rej(new Error('Task timed out.')); + rej(new TaskTimedOutError()); }, timeoutMs); }); @@ -125,7 +133,7 @@ export async function timeout( const timeoutPromise = new Promise((_, rej) => { const wait = setTimeout(() => { clearTimeout(wait); - rej(new Error('Task timed out.')); + rej(new TaskTimedOutError()); }, timeoutMs); }); diff --git a/ts/util/accountManager.ts b/ts/util/accountManager.ts index 5be45714c..93146342c 100644 --- a/ts/util/accountManager.ts +++ b/ts/util/accountManager.ts @@ -9,13 +9,13 @@ import { import { getOurPubKeyStrFromCache } from '../session/utils/User'; import { trigger } from '../shims/events'; import { - createOrUpdateItem, removeAllContactPreKeys, removeAllContactSignedPreKeys, removeAllPreKeys, removeAllSessions, removeAllSignedPreKeys, } from '../data/data'; +import { forceSyncConfigurationNowIfNeeded } from '../session/utils/syncUtils'; /** * Might throw @@ -167,6 +167,39 @@ export class AccountManager { ]); } + public static async deleteAccount(reason?: string) { + const deleteEverything = 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', reason || ''); + }; + try { + 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 deleteEverything(); + } catch (error) { + window.log.error( + 'Something went wrong deleting all data:', + error && error.stack ? error.stack : error + ); + try { + await deleteEverything(); + } catch (e) { + window.log.error(e); + } + } + window.restart(); + } + private static async createAccount(identityKeyPair: any) { const sodium = await getSodium(); let password = fromArrayBufferToBase64(sodium.randombytes_buf(16)); diff --git a/ts/window.d.ts b/ts/window.d.ts index b771004d1..ea0eb1920 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -46,7 +46,6 @@ declare global { clipboard: any; confirmationDialog: (params: ConfirmationDialogParams) => any; dcodeIO: any; - deleteAccount: any; displayNameRegex: any; friends: any; getConversations: any;