Merge branch 'clearnet' into registration-progress-banner
commit
ebb37b44b6
@ -1,239 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { PromiseUtils, StringUtils, ToastUtils, UserUtils } from '../../../session/utils';
|
|
||||||
import { getConversationController } from '../../../session/conversations';
|
|
||||||
import { createOrUpdateItem, removeAll } from '../../../data/data';
|
|
||||||
import { SignUpTab } from './SignUpTab';
|
|
||||||
import { SignInTab } from './SignInTab';
|
|
||||||
import { TabLabel, TabType } from './TabLabel';
|
|
||||||
import { trigger } from '../../../shims/events';
|
|
||||||
import {
|
|
||||||
generateMnemonic,
|
|
||||||
registerSingleDevice,
|
|
||||||
sessionGenerateKeyPair,
|
|
||||||
signInByLinkingDevice,
|
|
||||||
} from '../../../util/accountManager';
|
|
||||||
import { fromHex } from '../../../session/utils/String';
|
|
||||||
import { TaskTimedOutError } from '../../../session/utils/Promise';
|
|
||||||
import { mn_decode } from '../../../session/crypto/mnemonic';
|
|
||||||
import { getSwarmPollingInstance } from '../../../session/snode_api/swarmPolling';
|
|
||||||
|
|
||||||
export const MAX_USERNAME_LENGTH = 20;
|
|
||||||
// tslint:disable: use-simple-attributes
|
|
||||||
|
|
||||||
interface State {
|
|
||||||
selectedTab: TabType;
|
|
||||||
generatedRecoveryPhrase: string;
|
|
||||||
hexGeneratedPubKey: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function resetRegistration() {
|
|
||||||
await removeAll();
|
|
||||||
await window.storage.reset();
|
|
||||||
await window.storage.fetch();
|
|
||||||
getConversationController().reset();
|
|
||||||
await getConversationController().load();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns undefined if an error happened, or the trim userName.
|
|
||||||
*
|
|
||||||
* Be sure to use the trimmed userName for creating the account.
|
|
||||||
*/
|
|
||||||
const displayNameIsValid = (displayName: string): undefined | string => {
|
|
||||||
const trimName = displayName.trim();
|
|
||||||
|
|
||||||
if (!trimName) {
|
|
||||||
window?.log?.warn('invalid trimmed name for registration');
|
|
||||||
ToastUtils.pushToastError('invalidDisplayName', window.i18n('displayNameEmpty'));
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return trimName;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function signUp(signUpDetails: {
|
|
||||||
displayName: string;
|
|
||||||
generatedRecoveryPhrase: string;
|
|
||||||
}) {
|
|
||||||
const { displayName, generatedRecoveryPhrase } = signUpDetails;
|
|
||||||
window?.log?.info('SIGNING UP');
|
|
||||||
|
|
||||||
const trimName = displayNameIsValid(displayName);
|
|
||||||
// shows toast to user about the error
|
|
||||||
if (!trimName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await resetRegistration();
|
|
||||||
await registerSingleDevice(generatedRecoveryPhrase, 'english', trimName);
|
|
||||||
await createOrUpdateItem({
|
|
||||||
id: 'hasSyncedInitialConfigurationItem',
|
|
||||||
value: true,
|
|
||||||
});
|
|
||||||
trigger('openInbox');
|
|
||||||
} catch (e) {
|
|
||||||
await resetRegistration();
|
|
||||||
|
|
||||||
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 signInWithRecovery(signInDetails: {
|
|
||||||
displayName: string;
|
|
||||||
userRecoveryPhrase: string;
|
|
||||||
}) {
|
|
||||||
const { displayName, userRecoveryPhrase } = signInDetails;
|
|
||||||
window?.log?.info('RESTORING FROM SEED');
|
|
||||||
const trimName = displayNameIsValid(displayName);
|
|
||||||
// shows toast to user about the error
|
|
||||||
if (!trimName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await resetRegistration();
|
|
||||||
|
|
||||||
await registerSingleDevice(userRecoveryPhrase, 'english', trimName);
|
|
||||||
trigger('openInbox');
|
|
||||||
} catch (e) {
|
|
||||||
await resetRegistration();
|
|
||||||
ToastUtils.pushToastError('registrationError', `Error: ${e.message || 'Something went wrong'}`);
|
|
||||||
window?.log?.warn('exception during registration:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is will try to sign in with the user recovery phrase.
|
|
||||||
* If no ConfigurationMessage is received in 60seconds, the loading will be canceled.
|
|
||||||
*/
|
|
||||||
export async function signInWithLinking(signInDetails: { userRecoveryPhrase: string }) {
|
|
||||||
const { userRecoveryPhrase } = signInDetails;
|
|
||||||
window?.log?.info('LINKING DEVICE');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await resetRegistration();
|
|
||||||
await signInByLinkingDevice(userRecoveryPhrase, 'english');
|
|
||||||
let displayNameFromNetwork = '';
|
|
||||||
await getSwarmPollingInstance().start();
|
|
||||||
|
|
||||||
await PromiseUtils.waitForTask(done => {
|
|
||||||
window.Whisper.events.on('configurationMessageReceived', (displayName: string) => {
|
|
||||||
window.Whisper.events.off('configurationMessageReceived');
|
|
||||||
UserUtils.setSignInByLinking(false);
|
|
||||||
done(displayName);
|
|
||||||
|
|
||||||
displayNameFromNetwork = displayName;
|
|
||||||
});
|
|
||||||
}, 60000);
|
|
||||||
if (displayNameFromNetwork.length) {
|
|
||||||
// display name, avatars, groups and contacts should already be handled when this event was triggered.
|
|
||||||
window?.log?.info('We got a displayName from network: ');
|
|
||||||
} else {
|
|
||||||
window?.log?.info('Got a config message from network but without a displayName...');
|
|
||||||
throw new Error('Got a config message from network but without a displayName...');
|
|
||||||
}
|
|
||||||
// Do not set the lastProfileUpdateTimestamp.
|
|
||||||
// We expect to get a display name from a configuration message while we are loading messages of this user
|
|
||||||
trigger('openInbox');
|
|
||||||
} catch (e) {
|
|
||||||
await resetRegistration();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class RegistrationTabs extends React.Component<any, State> {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
selectedTab: TabType.SignUp,
|
|
||||||
generatedRecoveryPhrase: '',
|
|
||||||
hexGeneratedPubKey: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount() {
|
|
||||||
void this.generateMnemonicAndKeyPair();
|
|
||||||
void resetRegistration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { selectedTab } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="session-registration-container">
|
|
||||||
<div className="session-registration__tab-container">
|
|
||||||
<TabLabel
|
|
||||||
type={TabType.SignUp}
|
|
||||||
isSelected={selectedTab === TabType.SignUp}
|
|
||||||
onSelect={this.handleTabSelect}
|
|
||||||
/>
|
|
||||||
<TabLabel
|
|
||||||
type={TabType.SignIn}
|
|
||||||
isSelected={selectedTab === TabType.SignIn}
|
|
||||||
onSelect={this.handleTabSelect}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{this.renderSections()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async generateMnemonicAndKeyPair() {
|
|
||||||
if (this.state.generatedRecoveryPhrase === '') {
|
|
||||||
const mnemonic = await generateMnemonic();
|
|
||||||
|
|
||||||
let seedHex = mn_decode(mnemonic);
|
|
||||||
// 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);
|
|
||||||
const keyPair = await sessionGenerateKeyPair(seed);
|
|
||||||
const hexGeneratedPubKey = StringUtils.decode(keyPair.pubKey, 'hex');
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
generatedRecoveryPhrase: mnemonic,
|
|
||||||
hexGeneratedPubKey, // our 'frontend' sessionID
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly handleTabSelect = (tabType: TabType): void => {
|
|
||||||
this.setState({
|
|
||||||
selectedTab: tabType,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
private renderSections() {
|
|
||||||
const { selectedTab, generatedRecoveryPhrase, hexGeneratedPubKey } = this.state;
|
|
||||||
if (selectedTab === TabType.SignUp) {
|
|
||||||
return (
|
|
||||||
<SignUpTab
|
|
||||||
generatedRecoveryPhrase={generatedRecoveryPhrase}
|
|
||||||
hexGeneratedPubKey={hexGeneratedPubKey}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <SignInTab />;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue