mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
Move accountManager to typescript
This commit is contained in:
parent
fe684088de
commit
5d6d81b9ef
|
@ -83,7 +83,6 @@ module.exports = grunt => {
|
|||
'libtextsecure/helpers.js',
|
||||
'libtextsecure/stringview.js',
|
||||
'libtextsecure/event_target.js',
|
||||
'libtextsecure/account_manager.js',
|
||||
'libtextsecure/http-resources.js',
|
||||
'libtextsecure/message_receiver.js',
|
||||
'libtextsecure/task_with_timeout.js',
|
||||
|
|
|
@ -96,27 +96,6 @@
|
|||
Whisper.events = _.clone(Backbone.Events);
|
||||
Whisper.events.isListenedTo = eventName =>
|
||||
Whisper.events._events ? !!Whisper.events._events[eventName] : false;
|
||||
let accountManager;
|
||||
window.getAccountManager = () => {
|
||||
if (!accountManager) {
|
||||
const USERNAME = storage.get('number_id');
|
||||
const PASSWORD = storage.get('password');
|
||||
accountManager = new textsecure.AccountManager(USERNAME, PASSWORD);
|
||||
accountManager.addEventListener('registration', () => {
|
||||
const user = {
|
||||
ourNumber: libsession.Utils.UserUtils.getOurPubKeyStrFromCache(),
|
||||
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
|
||||
};
|
||||
Whisper.events.trigger('userChanged', user);
|
||||
|
||||
Whisper.Registration.markDone();
|
||||
window.log.info('dispatching registration event');
|
||||
Whisper.events.trigger('registration_done');
|
||||
});
|
||||
}
|
||||
return accountManager;
|
||||
};
|
||||
|
||||
const cancelInitializationMessage = Views.Initialization.setMessage();
|
||||
|
||||
window.log.info('Storage fetch');
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
/* global
|
||||
window,
|
||||
textsecure,
|
||||
libsignal,
|
||||
mnemonic,
|
||||
btoa,
|
||||
getString,
|
||||
Event,
|
||||
dcodeIO,
|
||||
StringView,
|
||||
Event,
|
||||
*/
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
window.textsecure = window.textsecure || {};
|
||||
|
||||
const ARCHIVE_AGE = 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
function AccountManager(username, password) {
|
||||
this.pending = Promise.resolve();
|
||||
}
|
||||
|
||||
function getNumber(numberId) {
|
||||
if (!numberId || !numberId.length) {
|
||||
return numberId;
|
||||
}
|
||||
|
||||
const parts = numberId.split('.');
|
||||
if (!parts.length) {
|
||||
return numberId;
|
||||
}
|
||||
|
||||
return parts[0];
|
||||
}
|
||||
|
||||
AccountManager.prototype = new textsecure.EventTarget();
|
||||
AccountManager.prototype.extend({
|
||||
constructor: AccountManager,
|
||||
registerSingleDevice(mnemonic, mnemonicLanguage, profileName) {
|
||||
const createAccount = this.createAccount.bind(this);
|
||||
const clearSessionsAndPreKeys = this.clearSessionsAndPreKeys.bind(this);
|
||||
const registrationDone = this.registrationDone.bind(this);
|
||||
let generateKeypair;
|
||||
if (mnemonic) {
|
||||
generateKeypair = () => {
|
||||
let seedHex = window.mnemonic.mn_decode(mnemonic, mnemonicLanguage);
|
||||
// handle shorter than 32 bytes seeds
|
||||
const privKeyHexLength = 32 * 2;
|
||||
if (seedHex.length !== privKeyHexLength) {
|
||||
seedHex = seedHex.concat('0'.repeat(32));
|
||||
seedHex = seedHex.substring(0, privKeyHexLength);
|
||||
}
|
||||
const seed = dcodeIO.ByteBuffer.wrap(seedHex, 'hex').toArrayBuffer();
|
||||
return window.sessionGenerateKeyPair(seed);
|
||||
};
|
||||
} else {
|
||||
generateKeypair = libsignal.KeyHelper.generateIdentityKeyPair;
|
||||
}
|
||||
return this.queueTask(() =>
|
||||
generateKeypair().then(async identityKeyPair =>
|
||||
createAccount(identityKeyPair)
|
||||
.then(() => this.saveRecoveryPhrase(mnemonic))
|
||||
.then(clearSessionsAndPreKeys)
|
||||
.then(() => {
|
||||
const pubKeyString = StringView.arrayBufferToHex(
|
||||
identityKeyPair.pubKey
|
||||
);
|
||||
registrationDone(pubKeyString, profileName);
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
queueTask(task) {
|
||||
const taskWithTimeout = textsecure.createTaskWithTimeout(task);
|
||||
this.pending = this.pending.then(taskWithTimeout, taskWithTimeout);
|
||||
|
||||
return this.pending;
|
||||
},
|
||||
async createAccount(identityKeyPair, userAgent, readReceipts) {
|
||||
let password = btoa(getString(libsignal.crypto.getRandomBytes(16)));
|
||||
password = password.substring(0, password.length - 2);
|
||||
|
||||
await Promise.all([
|
||||
textsecure.storage.remove('identityKey'),
|
||||
textsecure.storage.remove('signaling_key'),
|
||||
textsecure.storage.remove('password'),
|
||||
textsecure.storage.remove('registrationId'),
|
||||
textsecure.storage.remove('number_id'),
|
||||
textsecure.storage.remove('device_name'),
|
||||
textsecure.storage.remove('userAgent'),
|
||||
textsecure.storage.remove('read-receipt-setting'),
|
||||
textsecure.storage.remove('typing-indicators-setting'),
|
||||
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 = StringView.arrayBufferToHex(identityKeyPair.pubKey);
|
||||
|
||||
await textsecure.storage.put('identityKey', identityKeyPair);
|
||||
await textsecure.storage.put('password', password);
|
||||
if (userAgent) {
|
||||
await textsecure.storage.put('userAgent', userAgent);
|
||||
}
|
||||
|
||||
await textsecure.storage.put(
|
||||
'read-receipt-setting',
|
||||
Boolean(readReceipts)
|
||||
);
|
||||
|
||||
// Enable typing indicators by default
|
||||
await textsecure.storage.put('typing-indicators-setting', Boolean(true));
|
||||
|
||||
await textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
|
||||
},
|
||||
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([
|
||||
window.Signal.Data.removeAllPreKeys(),
|
||||
window.Signal.Data.removeAllSignedPreKeys(),
|
||||
window.Signal.Data.removeAllContactPreKeys(),
|
||||
window.Signal.Data.removeAllContactSignedPreKeys(),
|
||||
window.Signal.Data.removeAllSessions(),
|
||||
]);
|
||||
},
|
||||
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 = window.Signal.Crypto.getRandomBytes(seedSize);
|
||||
const hex = StringView.arrayBufferToHex(seed);
|
||||
return mnemonic.mn_encode(hex, language);
|
||||
},
|
||||
getCurrentRecoveryPhrase() {
|
||||
return textsecure.storage.get('mnemonic');
|
||||
},
|
||||
saveRecoveryPhrase(mnemonic) {
|
||||
return textsecure.storage.put('mnemonic', mnemonic);
|
||||
},
|
||||
async registrationDone(number, displayName) {
|
||||
window.log.info('registration done');
|
||||
|
||||
textsecure.storage.put('primaryDevicePubKey', number);
|
||||
|
||||
// Ensure that we always have a conversation for ourself
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(number, 'private');
|
||||
await conversation.setLokiProfile({ displayName });
|
||||
|
||||
this.dispatchEvent(new Event('registration'));
|
||||
},
|
||||
});
|
||||
textsecure.AccountManager = AccountManager;
|
||||
})();
|
|
@ -5,6 +5,7 @@
|
|||
<title>libtextsecure test runner</title>
|
||||
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="mocha">
|
||||
|
@ -25,13 +26,11 @@
|
|||
<script type="text/javascript" src="../event_target.js" data-cover></script>
|
||||
<script type="text/javascript" src="../helpers.js" data-cover></script>
|
||||
<script type="text/javascript" src="../stringview.js" data-cover></script>
|
||||
<script type="text/javascript" src="../account_manager.js" data-cover></script>
|
||||
<script type="text/javascript" src="../task_with_timeout.js" data-cover></script>
|
||||
|
||||
<script type="text/javascript" src="errors_test.js"></script>
|
||||
<script type="text/javascript" src="helpers_test.js"></script>
|
||||
<script type="text/javascript" src="task_with_timeout_test.js"></script>
|
||||
<script type="text/javascript" src="account_manager_test.js"></script>
|
||||
|
||||
<!-- Comment out to turn off code coverage. Useful for getting real callstacks. -->
|
||||
<!-- NOTE: blanket doesn't support modern syntax and will choke until we find a replacement. :0( -->
|
||||
|
@ -42,4 +41,5 @@
|
|||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -86,7 +86,7 @@ window.isBeforeVersion = (toCheck, baseVersion) => {
|
|||
};
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
window.CONSTANTS = new (function() {
|
||||
window.CONSTANTS = new (function () {
|
||||
this.MAX_GROUP_NAME_LENGTH = 64;
|
||||
this.DEFAULT_PUBLIC_CHAT_URL = appConfig.get('defaultPublicChatServer');
|
||||
this.MAX_LINKED_DEVICES = 1;
|
||||
|
@ -184,6 +184,7 @@ window.libsession = require('./ts/session');
|
|||
window.getConversationController =
|
||||
window.libsession.Conversations.ConversationController.getInstance;
|
||||
|
||||
|
||||
// We never do these in our code, so we'll prevent it everywhere
|
||||
window.open = () => null;
|
||||
// eslint-disable-next-line no-eval, no-multi-assign
|
||||
|
@ -377,7 +378,7 @@ window.callWorker = (fnName, ...args) => utilWorker.callWorker(fnName, ...args);
|
|||
|
||||
// Linux seems to periodically let the event loop stop, so this is a global workaround
|
||||
setInterval(() => {
|
||||
window.nodeSetImmediate(() => {});
|
||||
window.nodeSetImmediate(() => { });
|
||||
}, 1000);
|
||||
|
||||
const { autoOrientImage } = require('./js/modules/auto_orient_image');
|
||||
|
@ -458,9 +459,9 @@ if (process.env.USE_STUBBED_NETWORK) {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line no-extend-native,func-names
|
||||
Promise.prototype.ignore = function() {
|
||||
Promise.prototype.ignore = function () {
|
||||
// eslint-disable-next-line more/no-then
|
||||
this.then(() => {});
|
||||
this.then(() => { });
|
||||
};
|
||||
|
||||
if (
|
||||
|
|
|
@ -14,13 +14,13 @@ import { getTheme } from '../../state/selectors/theme';
|
|||
import { getOurNumber } from '../../state/selectors/user';
|
||||
import { UserUtils } from '../../session/utils';
|
||||
import {
|
||||
forceSyncConfigurationNowIfNeeded,
|
||||
syncConfigurationIfNeeded,
|
||||
} from '../../session/utils/syncUtils';
|
||||
import { DAYS } from '../../session/utils/Number';
|
||||
import { removeItemById } from '../../data/data';
|
||||
import { OnionPaths } from '../../session/onions';
|
||||
import { getMessageQueue } from '../../session/sending';
|
||||
import { AccountManager } from '../../util';
|
||||
// tslint:disable-next-line: no-import-side-effect no-submodule-imports
|
||||
|
||||
export enum SectionType {
|
||||
|
@ -77,7 +77,7 @@ class ActionsPanelPrivate extends React.Component<Props> {
|
|||
void this.showResetSessionIDDialogIfNeeded();
|
||||
|
||||
// remove existing prekeys, sign prekeys and sessions
|
||||
void window.getAccountManager().clearSessionsAndPreKeys();
|
||||
void AccountManager.clearSessionsAndPreKeys();
|
||||
|
||||
// trigger a sync message if needed for our other devices
|
||||
void syncConfigurationIfNeeded();
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
|
||||
import { SessionModal } from './SessionModal';
|
||||
import { SessionButton } from './SessionButton';
|
||||
import { ToastUtils } from '../../session/utils';
|
||||
import { ToastUtils, UserUtils } from '../../session/utils';
|
||||
import { DefaultTheme, withTheme } from 'styled-components';
|
||||
import { PasswordUtil } from '../../util';
|
||||
import { getPasswordHash } from '../../data/data';
|
||||
|
@ -192,8 +192,7 @@ class SessionSeedModalInner extends React.Component<Props, State> {
|
|||
return false;
|
||||
}
|
||||
|
||||
const manager = await window.getAccountManager();
|
||||
const recoveryPhrase = manager.getCurrentRecoveryPhrase();
|
||||
const recoveryPhrase = UserUtils.getCurrentRecoveryPhrase();
|
||||
|
||||
this.setState({
|
||||
recoveryPhrase,
|
||||
|
|
|
@ -8,6 +8,7 @@ import { SignInTab } from './SignInTab';
|
|||
import { TabLabel, TabType } from './TabLabel';
|
||||
import { PasswordUtil } from '../../../util';
|
||||
import { trigger } from '../../../shims/events';
|
||||
import { AccountManager } from '../../../util/accountManager';
|
||||
|
||||
export const MAX_USERNAME_LENGTH = 20;
|
||||
// tslint:disable: use-simple-attributes
|
||||
|
@ -70,7 +71,7 @@ export async function signUp(signUpDetails: {
|
|||
verifyPassword,
|
||||
generatedRecoveryPhrase,
|
||||
} = signUpDetails;
|
||||
window.log.info('starting Signing up');
|
||||
window.log.info('SIGNING UP');
|
||||
const trimName = displayName.trim();
|
||||
|
||||
if (!trimName) {
|
||||
|
@ -103,9 +104,77 @@ export async function signUp(signUpDetails: {
|
|||
await resetRegistration();
|
||||
await window.setPassword(password);
|
||||
UserUtils.setRestoringFromSeed(false);
|
||||
await window
|
||||
.getAccountManager()
|
||||
.registerSingleDevice(generatedRecoveryPhrase, 'english', trimName);
|
||||
await AccountManager.registerSingleDevice(
|
||||
generatedRecoveryPhrase,
|
||||
'english',
|
||||
trimName
|
||||
);
|
||||
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
||||
trigger('openInbox');
|
||||
} catch (e) {
|
||||
ToastUtils.pushToastError(
|
||||
'registrationError',
|
||||
`Error: ${e.message || 'Something went wrong'}`
|
||||
);
|
||||
window.log.warn('exception during registration:', e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign in/restore from seed.
|
||||
* Ask for a display name, as we will drop incoming ConfigurationMessages if any are saved on the swarm.
|
||||
* We will handle a ConfigurationMessage
|
||||
*/
|
||||
export async function restoreFromSeed(signInDetails: {
|
||||
displayName: string;
|
||||
userRecoveryPhrase: string;
|
||||
password: string;
|
||||
verifyPassword: string;
|
||||
}) {
|
||||
const {
|
||||
displayName,
|
||||
password,
|
||||
verifyPassword,
|
||||
userRecoveryPhrase,
|
||||
} = signInDetails;
|
||||
window.log.info('RESTORING FROM SEED');
|
||||
const trimName = displayName.trim();
|
||||
|
||||
if (!trimName) {
|
||||
window.log.warn('invalid trimmed name for registration');
|
||||
ToastUtils.pushToastError(
|
||||
'invalidDisplayName',
|
||||
window.i18n('displayNameEmpty')
|
||||
);
|
||||
return;
|
||||
}
|
||||
const passwordErrors = validatePassword(password, verifyPassword);
|
||||
if (passwordErrors.passwordErrorString) {
|
||||
window.log.warn('invalid password for registration');
|
||||
ToastUtils.pushToastError(
|
||||
'invalidPassword',
|
||||
window.i18n('invalidPassword')
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!!password && !passwordErrors.passwordFieldsMatch) {
|
||||
window.log.warn('passwords does not match for registration');
|
||||
ToastUtils.pushToastError(
|
||||
'invalidPassword',
|
||||
window.i18n('passwordsDoNotMatch')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await resetRegistration();
|
||||
await window.setPassword(password);
|
||||
UserUtils.setRestoringFromSeed(false);
|
||||
await AccountManager.registerSingleDevice(
|
||||
userRecoveryPhrase,
|
||||
'english',
|
||||
trimName
|
||||
);
|
||||
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
||||
trigger('openInbox');
|
||||
} catch (e) {
|
||||
|
@ -157,9 +226,7 @@ export class RegistrationTabs extends React.Component<any, State> {
|
|||
private async generateMnemonicAndKeyPair() {
|
||||
if (this.state.generatedRecoveryPhrase === '') {
|
||||
const language = 'english';
|
||||
const mnemonic = await window
|
||||
.getAccountManager()
|
||||
.generateMnemonic(language);
|
||||
const mnemonic = await AccountManager.generateMnemonic(language);
|
||||
|
||||
let seedHex = window.mnemonic.mn_decode(mnemonic, language);
|
||||
// handle shorter than 32 bytes seeds
|
||||
|
@ -206,7 +273,7 @@ export class RegistrationTabs extends React.Component<any, State> {
|
|||
return <SignInTab />;
|
||||
}
|
||||
|
||||
private async register() {
|
||||
// private async register() {
|
||||
// const {
|
||||
// password,
|
||||
// recoveryPhrase,
|
||||
|
@ -232,9 +299,7 @@ export class RegistrationTabs extends React.Component<any, State> {
|
|||
// await window.setPassword(password);
|
||||
// const isRestoringFromSeed = signInMode === SignInMode.UsingRecoveryPhrase;
|
||||
// UserUtils.setRestoringFromSeed(isRestoringFromSeed);
|
||||
// await window
|
||||
// .getAccountManager()
|
||||
// .registerSingleDevice(seedToUse, 'english', trimName);
|
||||
// await AccountManager.registerSingleDevice(seedToUse, 'english', trimName);
|
||||
// // if we are just creating a new account, no need to wait for a configuration message
|
||||
// if (!isRestoringFromSeed) {
|
||||
// trigger('openInbox');
|
||||
|
@ -250,14 +315,6 @@ export class RegistrationTabs extends React.Component<any, State> {
|
|||
// 'registrationError',
|
||||
// `Error: ${e.message || 'Something went wrong'}`
|
||||
// );
|
||||
// let exmsg = '';
|
||||
// if (e.message) {
|
||||
// exmsg += e.message;
|
||||
// }
|
||||
// if (e.stack) {
|
||||
// exmsg += ` | stack: + ${e.stack}`;
|
||||
// }
|
||||
// window.log.warn('exception during registration:', exmsg);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -556,7 +556,10 @@ export async function getConversationById(
|
|||
id: string
|
||||
): Promise<ConversationModel | undefined> {
|
||||
const data = await channels.getConversationById(id);
|
||||
if (data) {
|
||||
return new ConversationModel(data);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function updateConversation(
|
||||
|
|
|
@ -115,3 +115,11 @@ export function setLastProfileUpdateTimestamp(lastUpdateTimestamp: number) {
|
|||
lastUpdateTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
export function getCurrentRecoveryPhrase() {
|
||||
return window.textsecure.storage.get('mnemonic');
|
||||
}
|
||||
|
||||
export function saveRecoveryPhrase(mnemonic: string) {
|
||||
return window.textsecure.storage.put('mnemonic', mnemonic);
|
||||
}
|
||||
|
|
135
ts/util/accountManager.ts
Normal file
135
ts/util/accountManager.ts
Normal file
|
@ -0,0 +1,135 @@
|
|||
import { ConversationController } from '../session/conversations';
|
||||
import { getSodium } from '../session/crypto';
|
||||
import { UserUtils } from '../session/utils';
|
||||
import {
|
||||
fromArrayBufferToBase64,
|
||||
fromHex,
|
||||
toHex,
|
||||
} from '../session/utils/String';
|
||||
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
||||
import { trigger } from '../shims/events';
|
||||
|
||||
const generateKeypair = async (mnemonic: string, mnemonicLanguage: string) => {
|
||||
let seedHex = window.mnemonic.mn_decode(mnemonic, mnemonicLanguage);
|
||||
// handle shorter than 32 bytes seeds
|
||||
const privKeyHexLength = 32 * 2;
|
||||
if (seedHex.length !== privKeyHexLength) {
|
||||
seedHex = seedHex.concat('0'.repeat(32));
|
||||
seedHex = seedHex.substring(0, privKeyHexLength);
|
||||
}
|
||||
const seed = fromHex(seedHex);
|
||||
console.warn('generateKeypair seedHex', seedHex);
|
||||
console.warn('generateKeypair seed', seed);
|
||||
return window.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 {
|
||||
public static async registerSingleDevice(
|
||||
mnemonic: string,
|
||||
mnemonicLanguage: string,
|
||||
profileName: string
|
||||
) {
|
||||
const createAccount = this.createAccount.bind(this);
|
||||
const clearSessionsAndPreKeys = this.clearSessionsAndPreKeys.bind(this);
|
||||
const registrationDone = this.registrationDone.bind(this);
|
||||
if (!mnemonic) {
|
||||
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(mnemonic, mnemonicLanguage);
|
||||
await createAccount(identityKeyPair);
|
||||
UserUtils.saveRecoveryPhrase(mnemonic);
|
||||
await clearSessionsAndPreKeys();
|
||||
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 = window.Signal.Crypto.getRandomBytes(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([
|
||||
window.Signal.Data.removeAllPreKeys(),
|
||||
window.Signal.Data.removeAllSignedPreKeys(),
|
||||
window.Signal.Data.removeAllContactPreKeys(),
|
||||
window.Signal.Data.removeAllContactSignedPreKeys(),
|
||||
window.Signal.Data.removeAllSessions(),
|
||||
]);
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
|
||||
}
|
||||
|
||||
private static async registrationDone(number: string, displayName: string) {
|
||||
window.log.info('registration done');
|
||||
|
||||
window.textsecure.storage.put('primaryDevicePubKey', number);
|
||||
|
||||
// Ensure that we always have a conversation for ourself
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
number,
|
||||
'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,6 +10,7 @@ import * as AttachmentUtil from './attachmentsUtil';
|
|||
import * as LinkPreviewUtil from './linkPreviewFetch';
|
||||
|
||||
export * from './blockedNumberController';
|
||||
export * from './accountManager';
|
||||
|
||||
export {
|
||||
arrayBufferToObjectURL,
|
||||
|
|
1
ts/window.d.ts
vendored
1
ts/window.d.ts
vendored
|
@ -49,7 +49,6 @@ declare global {
|
|||
deleteAccount: any;
|
||||
displayNameRegex: any;
|
||||
friends: any;
|
||||
getAccountManager: any;
|
||||
getConversations: any;
|
||||
getFriendsFromContacts: any;
|
||||
getSettingValue: any;
|
||||
|
|
Loading…
Reference in a new issue