make AccountManager functions only rather than full static class

pull/1512/head
Audric Ackermann 4 years ago
parent 4a794e90a0
commit 8c33d89057
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -22,7 +22,7 @@ import {
} from '../../data/data'; } from '../../data/data';
import { OnionPaths } from '../../session/onions'; import { OnionPaths } from '../../session/onions';
import { getMessageQueue } from '../../session/sending'; import { getMessageQueue } from '../../session/sending';
import { AccountManager } from '../../util'; import { clearSessionsAndPreKeys } from '../../util/accountManager';
// tslint:disable-next-line: no-import-side-effect no-submodule-imports // tslint:disable-next-line: no-import-side-effect no-submodule-imports
export enum SectionType { export enum SectionType {
@ -90,7 +90,7 @@ class ActionsPanelPrivate extends React.Component<Props> {
void this.showResetSessionIDDialogIfNeeded(); void this.showResetSessionIDDialogIfNeeded();
// remove existing prekeys, sign prekeys and sessions // remove existing prekeys, sign prekeys and sessions
void AccountManager.clearSessionsAndPreKeys(); void clearSessionsAndPreKeys();
// Do this only if we created a new Session ID, or if we already received the initial configuration message // Do this only if we created a new Session ID, or if we already received the initial configuration message

@ -14,7 +14,7 @@ import { SessionSearchInput } from './SessionSearchInput';
import { SessionSettingCategory } from './settings/SessionSettings'; import { SessionSettingCategory } from './settings/SessionSettings';
import { DefaultTheme } from 'styled-components'; import { DefaultTheme } from 'styled-components';
import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader';
import { AccountManager } from '../../util'; import { deleteAccount } from '../../util/accountManager';
interface Props { interface Props {
settingsCategory: SessionSettingCategory; settingsCategory: SessionSettingCategory;
@ -180,7 +180,7 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
title, title,
message, message,
messageSub, messageSub,
resolve: AccountManager.deleteAccount, resolve: deleteAccount,
okTheme: 'danger', okTheme: 'danger',
}); });
} }

@ -4,7 +4,7 @@ import { SessionModal } from './SessionModal';
import { SessionButton, SessionButtonColor } from './SessionButton'; import { SessionButton, SessionButtonColor } from './SessionButton';
import { DefaultTheme, withTheme } from 'styled-components'; import { DefaultTheme, withTheme } from 'styled-components';
import { SessionIcon, SessionIconSize, SessionIconType } from './icon'; import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
import { AccountManager } from '../../util'; import { deleteAccount } from '../../util/accountManager';
type Props = { type Props = {
onClose: any; onClose: any;
@ -41,7 +41,7 @@ const SessionIDResetDialogInner = (props: Props) => {
<SessionButton <SessionButton
text="Upgrade Now" text="Upgrade Now"
onClick={() => { onClick={() => {
void AccountManager.deleteAccount('Session ID Upgrade'); void deleteAccount('Session ID Upgrade');
props.onClose(); props.onClose();
}} }}
buttonColor={SessionButtonColor.Danger} buttonColor={SessionButtonColor.Danger}

@ -14,10 +14,12 @@ import { TabLabel, TabType } from './TabLabel';
import { PasswordUtil } from '../../../util'; import { PasswordUtil } from '../../../util';
import { trigger } from '../../../shims/events'; import { trigger } from '../../../shims/events';
import { import {
AccountManager, generateMnemonic,
registerSingleDevice,
sessionGenerateKeyPair, sessionGenerateKeyPair,
signInByLinkingDevice,
} from '../../../util/accountManager'; } from '../../../util/accountManager';
import { fromHex, fromHexToArray } from '../../../session/utils/String'; import { fromHex } from '../../../session/utils/String';
import { TaskTimedOutError } from '../../../session/utils/Promise'; import { TaskTimedOutError } from '../../../session/utils/Promise';
export const MAX_USERNAME_LENGTH = 20; export const MAX_USERNAME_LENGTH = 20;
@ -138,11 +140,7 @@ export async function signUp(signUpDetails: {
try { try {
await resetRegistration(); await resetRegistration();
await window.setPassword(password); await window.setPassword(password);
await AccountManager.registerSingleDevice( await registerSingleDevice(generatedRecoveryPhrase, 'english', trimName);
generatedRecoveryPhrase,
'english',
trimName
);
await createOrUpdateItem({ await createOrUpdateItem({
id: 'hasSyncedInitialConfigurationItem', id: 'hasSyncedInitialConfigurationItem',
value: true, value: true,
@ -191,11 +189,7 @@ export async function signInWithRecovery(signInDetails: {
await resetRegistration(); await resetRegistration();
await window.setPassword(password); await window.setPassword(password);
await AccountManager.registerSingleDevice( await registerSingleDevice(userRecoveryPhrase, 'english', trimName);
userRecoveryPhrase,
'english',
trimName
);
trigger('openInbox'); trigger('openInbox');
} catch (e) { } catch (e) {
await resetRegistration(); await resetRegistration();
@ -225,7 +219,7 @@ export async function signInWithLinking(signInDetails: {
try { try {
await resetRegistration(); await resetRegistration();
await window.setPassword(password); await window.setPassword(password);
await AccountManager.signInByLinkingDevice(userRecoveryPhrase, 'english'); await signInByLinkingDevice(userRecoveryPhrase, 'english');
let displayNameFromNetwork = ''; let displayNameFromNetwork = '';
@ -311,7 +305,7 @@ export class RegistrationTabs extends React.Component<any, State> {
private async generateMnemonicAndKeyPair() { private async generateMnemonicAndKeyPair() {
if (this.state.generatedRecoveryPhrase === '') { if (this.state.generatedRecoveryPhrase === '') {
const language = 'english'; const language = 'english';
const mnemonic = await AccountManager.generateMnemonic(language); const mnemonic = await generateMnemonic(language);
let seedHex = window.mnemonic.mn_decode(mnemonic, language); let seedHex = window.mnemonic.mn_decode(mnemonic, language);
// handle shorter than 32 bytes seeds // handle shorter than 32 bytes seeds

@ -59,203 +59,192 @@ const generateKeypair = async (mnemonic: string, mnemonicLanguage: string) => {
return sessionGenerateKeyPair(seed); return sessionGenerateKeyPair(seed);
}; };
// TODO not sure why AccountManager was a singleton before. Can we get rid of it as a singleton? /**
// tslint:disable-next-line: no-unnecessary-class * Sign in with a recovery phrase. We won't try to recover an existing profile name
export class AccountManager { * @param mnemonic the mnemonic the user duly saved in a safe place. We will restore his sessionID based on this.
/** * @param mnemonicLanguage 'english' only is supported
* Sign in with a recovery phrase. We won't try to recover an existing profile name * @param profileName the displayName to use for this user
* @param mnemonic the mnemonic the user duly saved in a safe place. We will restore his sessionID based on this. */
* @param mnemonicLanguage 'english' only is supported export async function signInWithRecovery(
* @param profileName the displayName to use for this user mnemonic: string,
*/ mnemonicLanguage: string,
public static async signInWithRecovery( profileName: string
mnemonic: string, ) {
mnemonicLanguage: string, return registerSingleDevice(mnemonic, mnemonicLanguage, profileName);
profileName: string }
) {
return AccountManager.registerSingleDevice( /**
mnemonic, * Sign in with a recovery phrase but trying to recover display name and avatar from the first encountered configuration message.
mnemonicLanguage, * @param mnemonic the mnemonic the user duly saved in a safe place. We will restore his sessionID based on this.
profileName * @param mnemonicLanguage 'english' only is supported
*/
export async function signInByLinkingDevice(
mnemonic: string,
mnemonicLanguage: string
) {
if (!mnemonic) {
throw new Error(
'Session always needs a mnemonic. Either generated or given by the user'
); );
} }
if (!mnemonicLanguage) {
throw new Error('We always needs a mnemonicLanguage');
}
/** const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
* Sign in with a recovery phrase but trying to recover display name and avatar from the first encountered configuration message. UserUtils.setSignInByLinking(true);
* @param mnemonic the mnemonic the user duly saved in a safe place. We will restore his sessionID based on this. await createAccount(identityKeyPair);
* @param mnemonicLanguage 'english' only is supported UserUtils.saveRecoveryPhrase(mnemonic);
*/ await clearSessionsAndPreKeys();
public static async signInByLinkingDevice( const pubKeyString = toHex(identityKeyPair.pubKey);
mnemonic: string,
mnemonicLanguage: string
) {
if (!mnemonic) {
throw new Error(
'Session always needs a mnemonic. Either generated or given by the user'
);
}
if (!mnemonicLanguage) {
throw new Error('We always needs a mnemonicLanguage');
}
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
UserUtils.setSignInByLinking(true);
await AccountManager.createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(mnemonic);
await AccountManager.clearSessionsAndPreKeys();
const pubKeyString = toHex(identityKeyPair.pubKey);
// await for the first configuration message to come in. // await for the first configuration message to come in.
await AccountManager.registrationDone(pubKeyString, ''); await registrationDone(pubKeyString, '');
}
/**
* This is a signup. User has no recovery and does not try to link a device
* @param mnemonic The mnemonic generated on first app loading and to use for this brand new user
* @param mnemonicLanguage only 'english' is supported
* @param profileName the display name to register toi
*/
export async function registerSingleDevice(
generatedMnemonic: string,
mnemonicLanguage: string,
profileName: string
) {
if (!generatedMnemonic) {
throw new Error(
'Session always needs a mnemonic. Either generated or given by the user'
);
}
if (!profileName) {
throw new Error('We always needs a profileName');
}
if (!mnemonicLanguage) {
throw new Error('We always needs a mnemonicLanguage');
} }
/**
* This is a signup. User has no recovery and does not try to link a device
* @param mnemonic The mnemonic generated on first app loading and to use for this brand new user
* @param mnemonicLanguage only 'english' is supported
* @param profileName the display name to register toi
*/
public static async registerSingleDevice(
generatedMnemonic: string,
mnemonicLanguage: string,
profileName: string
) {
if (!generatedMnemonic) {
throw new Error(
'Session always needs a mnemonic. Either generated or given by the user'
);
}
if (!profileName) {
throw new Error('We always needs a profileName');
}
if (!mnemonicLanguage) {
throw new Error('We always needs a mnemonicLanguage');
}
const identityKeyPair = await generateKeypair( const identityKeyPair = await generateKeypair(
generatedMnemonic, generatedMnemonic,
mnemonicLanguage mnemonicLanguage
); );
await AccountManager.createAccount(identityKeyPair); await createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(generatedMnemonic); UserUtils.saveRecoveryPhrase(generatedMnemonic);
await AccountManager.clearSessionsAndPreKeys(); await clearSessionsAndPreKeys();
await UserUtils.setLastProfileUpdateTimestamp(Date.now()); await UserUtils.setLastProfileUpdateTimestamp(Date.now());
const pubKeyString = toHex(identityKeyPair.pubKey); const pubKeyString = toHex(identityKeyPair.pubKey);
await AccountManager.registrationDone(pubKeyString, profileName); await registrationDone(pubKeyString, profileName);
} }
public static async generateMnemonic(language = 'english') { export async function generateMnemonic(language = 'english') {
// Note: 4 bytes are converted into 3 seed words, so length 12 seed words // Note: 4 bytes are converted into 3 seed words, so length 12 seed words
// (13 - 1 checksum) are generated using 12 * 4 / 3 = 16 bytes. // (13 - 1 checksum) are generated using 12 * 4 / 3 = 16 bytes.
const seedSize = 16; const seedSize = 16;
const seed = (await getSodium()).randombytes_buf(seedSize); const seed = (await getSodium()).randombytes_buf(seedSize);
const hex = toHex(seed); const hex = toHex(seed);
return window.mnemonic.mn_encode(hex, language); return window.mnemonic.mn_encode(hex, language);
} }
public static async clearSessionsAndPreKeys() { export async function clearSessionsAndPreKeys() {
window.log.info('clearing all sessions'); window.log.info('clearing all sessions');
// During secondary device registration we need to keep our prekeys sent // During secondary device registration we need to keep our prekeys sent
// to other pubkeys // to other pubkeys
await Promise.all([ await Promise.all([
removeAllPreKeys(), removeAllPreKeys(),
removeAllSignedPreKeys(), removeAllSignedPreKeys(),
removeAllContactPreKeys(), removeAllContactPreKeys(),
removeAllContactSignedPreKeys(), removeAllContactSignedPreKeys(),
removeAllSessions(), removeAllSessions(),
]); ]);
} }
public static async deleteAccount(reason?: string) { export async function deleteAccount(reason?: string) {
const deleteEverything = async () => { const deleteEverything = async () => {
window.log.info( window.log.info(
'configuration message sent successfully. Deleting everything' 'configuration message sent successfully. Deleting everything'
); );
await window.Signal.Logs.deleteAll(); await window.Signal.Logs.deleteAll();
await window.Signal.Data.removeAll(); await window.Signal.Data.removeAll();
await window.Signal.Data.close(); await window.Signal.Data.close();
await window.Signal.Data.removeDB(); await window.Signal.Data.removeDB();
await window.Signal.Data.removeOtherData(); await window.Signal.Data.removeOtherData();
// 'unlink' => toast will be shown on app restart // 'unlink' => toast will be shown on app restart
window.localStorage.setItem('restart-reason', reason || ''); 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 { 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(); await deleteEverything();
} catch (error) { } catch (e) {
window.log.error( window.log.error(e);
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
try {
await deleteEverything();
} catch (e) {
window.log.error(e);
}
} }
window.restart();
} }
window.restart();
}
private static async createAccount(identityKeyPair: any) { async function createAccount(identityKeyPair: any) {
const sodium = await getSodium(); const sodium = await getSodium();
let password = fromArrayBufferToBase64(sodium.randombytes_buf(16)); let password = fromArrayBufferToBase64(sodium.randombytes_buf(16));
password = password.substring(0, password.length - 2); password = password.substring(0, password.length - 2);
await Promise.all([ await Promise.all([
window.textsecure.storage.remove('identityKey'), window.textsecure.storage.remove('identityKey'),
window.textsecure.storage.remove('signaling_key'), window.textsecure.storage.remove('signaling_key'),
window.textsecure.storage.remove('password'), window.textsecure.storage.remove('password'),
window.textsecure.storage.remove('registrationId'), window.textsecure.storage.remove('registrationId'),
window.textsecure.storage.remove('number_id'), window.textsecure.storage.remove('number_id'),
window.textsecure.storage.remove('device_name'), window.textsecure.storage.remove('device_name'),
window.textsecure.storage.remove('userAgent'), window.textsecure.storage.remove('userAgent'),
window.textsecure.storage.remove('read-receipt-setting'), window.textsecure.storage.remove('read-receipt-setting'),
window.textsecure.storage.remove('typing-indicators-setting'), window.textsecure.storage.remove('typing-indicators-setting'),
window.textsecure.storage.remove('regionCode'), window.textsecure.storage.remove('regionCode'),
]); ]);
// update our own identity key, which may have changed // update our own identity key, which may have changed
// if we're relinking after a reinstall on the master device // if we're relinking after a reinstall on the master device
const pubKeyString = toHex(identityKeyPair.pubKey); const pubKeyString = toHex(identityKeyPair.pubKey);
await window.textsecure.storage.put('identityKey', identityKeyPair); await window.textsecure.storage.put('identityKey', identityKeyPair);
await window.textsecure.storage.put('password', password); await window.textsecure.storage.put('password', password);
await window.textsecure.storage.put('read-receipt-setting', false); await window.textsecure.storage.put('read-receipt-setting', false);
// Enable typing indicators by default // Enable typing indicators by default
await window.textsecure.storage.put( await window.textsecure.storage.put(
'typing-indicators-setting', 'typing-indicators-setting',
Boolean(true) Boolean(true)
); );
await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1); await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
} }
private static async registrationDone( async function registrationDone(ourPubkey: string, displayName: string) {
ourPubkey: string, window.log.info('registration done');
displayName: string
) {
window.log.info('registration done');
window.textsecure.storage.put('primaryDevicePubKey', ourPubkey); window.textsecure.storage.put('primaryDevicePubKey', ourPubkey);
// Ensure that we always have a conversation for ourself // Ensure that we always have a conversation for ourself
const conversation = await ConversationController.getInstance().getOrCreateAndWait( const conversation = await ConversationController.getInstance().getOrCreateAndWait(
ourPubkey, ourPubkey,
'private' 'private'
); );
await conversation.setLokiProfile({ displayName }); await conversation.setLokiProfile({ displayName });
const user = { const user = {
ourNumber: getOurPubKeyStrFromCache(), ourNumber: getOurPubKeyStrFromCache(),
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'), ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
}; };
trigger('userChanged', user); trigger('userChanged', user);
window.Whisper.Registration.markDone(); window.Whisper.Registration.markDone();
window.log.info('dispatching registration event'); window.log.info('dispatching registration event');
trigger('registration_done'); trigger('registration_done');
}
} }

@ -10,7 +10,6 @@ import * as AttachmentUtil from './attachmentsUtil';
import * as LinkPreviewUtil from './linkPreviewFetch'; import * as LinkPreviewUtil from './linkPreviewFetch';
export * from './blockedNumberController'; export * from './blockedNumberController';
export * from './accountManager';
export { export {
arrayBufferToObjectURL, arrayBufferToObjectURL,

Loading…
Cancel
Save