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';
import { OnionPaths } from '../../session/onions';
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
export enum SectionType {
@ -90,7 +90,7 @@ class ActionsPanelPrivate extends React.Component<Props> {
void this.showResetSessionIDDialogIfNeeded();
// 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

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

@ -4,7 +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';
import { deleteAccount } from '../../util/accountManager';
type Props = {
onClose: any;
@ -41,7 +41,7 @@ const SessionIDResetDialogInner = (props: Props) => {
<SessionButton
text="Upgrade Now"
onClick={() => {
void AccountManager.deleteAccount('Session ID Upgrade');
void deleteAccount('Session ID Upgrade');
props.onClose();
}}
buttonColor={SessionButtonColor.Danger}

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

@ -59,203 +59,192 @@ const generateKeypair = async (mnemonic: string, mnemonicLanguage: string) => {
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
export class AccountManager {
/**
* Sign in with a recovery phrase. We won't try to recover an existing profile name
* @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
* @param profileName the displayName to use for this user
*/
public static async signInWithRecovery(
mnemonic: string,
mnemonicLanguage: string,
profileName: string
) {
return AccountManager.registerSingleDevice(
mnemonic,
mnemonicLanguage,
profileName
/**
* Sign in with a recovery phrase. We won't try to recover an existing profile name
* @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
* @param profileName the displayName to use for this user
*/
export async function signInWithRecovery(
mnemonic: string,
mnemonicLanguage: string,
profileName: string
) {
return registerSingleDevice(mnemonic, mnemonicLanguage, profileName);
}
/**
* Sign in with a recovery phrase but trying to recover display name and avatar from the first encountered configuration message.
* @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 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');
}
/**
* Sign in with a recovery phrase but trying to recover display name and avatar from the first encountered configuration message.
* @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
*/
public static async 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);
UserUtils.setSignInByLinking(true);
await AccountManager.createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(mnemonic);
await AccountManager.clearSessionsAndPreKeys();
const pubKeyString = toHex(identityKeyPair.pubKey);
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
UserUtils.setSignInByLinking(true);
await createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(mnemonic);
await clearSessionsAndPreKeys();
const pubKeyString = toHex(identityKeyPair.pubKey);
// await for the first configuration message to come in.
await AccountManager.registrationDone(pubKeyString, '');
// await for the first configuration message to come in.
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(
generatedMnemonic,
mnemonicLanguage
);
const identityKeyPair = await generateKeypair(
generatedMnemonic,
mnemonicLanguage
);
await AccountManager.createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(generatedMnemonic);
await AccountManager.clearSessionsAndPreKeys();
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
await createAccount(identityKeyPair);
UserUtils.saveRecoveryPhrase(generatedMnemonic);
await clearSessionsAndPreKeys();
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
const pubKeyString = toHex(identityKeyPair.pubKey);
await AccountManager.registrationDone(pubKeyString, profileName);
}
const pubKeyString = toHex(identityKeyPair.pubKey);
await registrationDone(pubKeyString, profileName);
}
public static async generateMnemonic(language = 'english') {
// 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.
const seedSize = 16;
const seed = (await getSodium()).randombytes_buf(seedSize);
const hex = toHex(seed);
return window.mnemonic.mn_encode(hex, language);
}
export async function generateMnemonic(language = 'english') {
// 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.
const seedSize = 16;
const seed = (await getSodium()).randombytes_buf(seedSize);
const hex = toHex(seed);
return window.mnemonic.mn_encode(hex, language);
}
public static async clearSessionsAndPreKeys() {
window.log.info('clearing all sessions');
// During secondary device registration we need to keep our prekeys sent
// to other pubkeys
await Promise.all([
removeAllPreKeys(),
removeAllSignedPreKeys(),
removeAllContactPreKeys(),
removeAllContactSignedPreKeys(),
removeAllSessions(),
]);
}
export async function clearSessionsAndPreKeys() {
window.log.info('clearing all sessions');
// During secondary device registration we need to keep our prekeys sent
// to other pubkeys
await Promise.all([
removeAllPreKeys(),
removeAllSignedPreKeys(),
removeAllContactPreKeys(),
removeAllContactSignedPreKeys(),
removeAllSessions(),
]);
}
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 || '');
};
export async function 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 {
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);
}
} catch (e) {
window.log.error(e);
}
window.restart();
}
window.restart();
}
private static async createAccount(identityKeyPair: any) {
const sodium = await getSodium();
let password = fromArrayBufferToBase64(sodium.randombytes_buf(16));
password = password.substring(0, password.length - 2);
await Promise.all([
window.textsecure.storage.remove('identityKey'),
window.textsecure.storage.remove('signaling_key'),
window.textsecure.storage.remove('password'),
window.textsecure.storage.remove('registrationId'),
window.textsecure.storage.remove('number_id'),
window.textsecure.storage.remove('device_name'),
window.textsecure.storage.remove('userAgent'),
window.textsecure.storage.remove('read-receipt-setting'),
window.textsecure.storage.remove('typing-indicators-setting'),
window.textsecure.storage.remove('regionCode'),
]);
// update our own identity key, which may have changed
// if we're relinking after a reinstall on the master device
const pubKeyString = toHex(identityKeyPair.pubKey);
await window.textsecure.storage.put('identityKey', identityKeyPair);
await window.textsecure.storage.put('password', password);
await window.textsecure.storage.put('read-receipt-setting', false);
// Enable typing indicators by default
await window.textsecure.storage.put(
'typing-indicators-setting',
Boolean(true)
);
async function createAccount(identityKeyPair: any) {
const sodium = await getSodium();
let password = fromArrayBufferToBase64(sodium.randombytes_buf(16));
password = password.substring(0, password.length - 2);
await Promise.all([
window.textsecure.storage.remove('identityKey'),
window.textsecure.storage.remove('signaling_key'),
window.textsecure.storage.remove('password'),
window.textsecure.storage.remove('registrationId'),
window.textsecure.storage.remove('number_id'),
window.textsecure.storage.remove('device_name'),
window.textsecure.storage.remove('userAgent'),
window.textsecure.storage.remove('read-receipt-setting'),
window.textsecure.storage.remove('typing-indicators-setting'),
window.textsecure.storage.remove('regionCode'),
]);
// update our own identity key, which may have changed
// if we're relinking after a reinstall on the master device
const pubKeyString = toHex(identityKeyPair.pubKey);
await window.textsecure.storage.put('identityKey', identityKeyPair);
await window.textsecure.storage.put('password', password);
await window.textsecure.storage.put('read-receipt-setting', false);
// Enable typing indicators by default
await window.textsecure.storage.put(
'typing-indicators-setting',
Boolean(true)
);
await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
}
await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
}
private static async registrationDone(
ourPubkey: string,
displayName: string
) {
window.log.info('registration done');
async function registrationDone(ourPubkey: string, 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
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
ourPubkey,
'private'
);
await conversation.setLokiProfile({ displayName });
const user = {
ourNumber: getOurPubKeyStrFromCache(),
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
};
trigger('userChanged', user);
window.Whisper.Registration.markDone();
window.log.info('dispatching registration event');
trigger('registration_done');
}
// Ensure that we always have a conversation for ourself
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
ourPubkey,
'private'
);
await conversation.setLokiProfile({ displayName });
const user = {
ourNumber: getOurPubKeyStrFromCache(),
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
};
trigger('userChanged', user);
window.Whisper.Registration.markDone();
window.log.info('dispatching registration event');
trigger('registration_done');
}

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

Loading…
Cancel
Save