|
|
@ -59,36 +59,29 @@ 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
|
|
|
|
|
|
|
|
export class AccountManager {
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Sign in with a recovery phrase. We won't try to recover an existing profile name
|
|
|
|
* 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 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 mnemonicLanguage 'english' only is supported
|
|
|
|
* @param profileName the displayName to use for this user
|
|
|
|
* @param profileName the displayName to use for this user
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static async signInWithRecovery(
|
|
|
|
export async function signInWithRecovery(
|
|
|
|
mnemonic: string,
|
|
|
|
mnemonic: string,
|
|
|
|
mnemonicLanguage: string,
|
|
|
|
mnemonicLanguage: string,
|
|
|
|
profileName: string
|
|
|
|
profileName: string
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
return AccountManager.registerSingleDevice(
|
|
|
|
return registerSingleDevice(mnemonic, mnemonicLanguage, profileName);
|
|
|
|
mnemonic,
|
|
|
|
}
|
|
|
|
mnemonicLanguage,
|
|
|
|
|
|
|
|
profileName
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Sign in with a recovery phrase but trying to recover display name and avatar from the first encountered configuration message.
|
|
|
|
* 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 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 mnemonicLanguage 'english' only is supported
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static async signInByLinkingDevice(
|
|
|
|
export async function signInByLinkingDevice(
|
|
|
|
mnemonic: string,
|
|
|
|
mnemonic: string,
|
|
|
|
mnemonicLanguage: string
|
|
|
|
mnemonicLanguage: string
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
if (!mnemonic) {
|
|
|
|
if (!mnemonic) {
|
|
|
|
throw new Error(
|
|
|
|
throw new Error(
|
|
|
|
'Session always needs a mnemonic. Either generated or given by the user'
|
|
|
|
'Session always needs a mnemonic. Either generated or given by the user'
|
|
|
@ -100,25 +93,25 @@ export class AccountManager {
|
|
|
|
|
|
|
|
|
|
|
|
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
|
|
|
|
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
|
|
|
|
UserUtils.setSignInByLinking(true);
|
|
|
|
UserUtils.setSignInByLinking(true);
|
|
|
|
await AccountManager.createAccount(identityKeyPair);
|
|
|
|
await createAccount(identityKeyPair);
|
|
|
|
UserUtils.saveRecoveryPhrase(mnemonic);
|
|
|
|
UserUtils.saveRecoveryPhrase(mnemonic);
|
|
|
|
await AccountManager.clearSessionsAndPreKeys();
|
|
|
|
await clearSessionsAndPreKeys();
|
|
|
|
const pubKeyString = toHex(identityKeyPair.pubKey);
|
|
|
|
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
|
|
|
|
* 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 mnemonic The mnemonic generated on first app loading and to use for this brand new user
|
|
|
|
* @param mnemonicLanguage only 'english' is supported
|
|
|
|
* @param mnemonicLanguage only 'english' is supported
|
|
|
|
* @param profileName the display name to register toi
|
|
|
|
* @param profileName the display name to register toi
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static async registerSingleDevice(
|
|
|
|
export async function registerSingleDevice(
|
|
|
|
generatedMnemonic: string,
|
|
|
|
generatedMnemonic: string,
|
|
|
|
mnemonicLanguage: string,
|
|
|
|
mnemonicLanguage: string,
|
|
|
|
profileName: string
|
|
|
|
profileName: string
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
if (!generatedMnemonic) {
|
|
|
|
if (!generatedMnemonic) {
|
|
|
|
throw new Error(
|
|
|
|
throw new Error(
|
|
|
|
'Session always needs a mnemonic. Either generated or given by the user'
|
|
|
|
'Session always needs a mnemonic. Either generated or given by the user'
|
|
|
@ -136,25 +129,25 @@ export class AccountManager {
|
|
|
|
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
|
|
|
@ -165,9 +158,9 @@ export class AccountManager {
|
|
|
|
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'
|
|
|
@ -198,9 +191,9 @@ export class AccountManager {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
@ -233,12 +226,9 @@ export class AccountManager {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
displayName: string
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
window.log.info('registration done');
|
|
|
|
window.log.info('registration done');
|
|
|
|
|
|
|
|
|
|
|
|
window.textsecure.storage.put('primaryDevicePubKey', ourPubkey);
|
|
|
|
window.textsecure.storage.put('primaryDevicePubKey', ourPubkey);
|
|
|
@ -257,5 +247,4 @@ export class AccountManager {
|
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|