session-desktop/ts/components/session/SessionSeedModal.tsx
2020-03-31 14:30:53 +11:00

228 lines
5 KiB
TypeScript

import React from 'react';
import { SessionModal } from './SessionModal';
import { SessionButton } from './SessionButton';
interface Props {
onClose: any;
}
interface State {
error: string;
loadingPassword: boolean;
loadingSeed: boolean;
seed: string;
hasPassword: boolean | null;
passwordHash: string;
passwordValid: boolean;
}
export class SessionSeedModal extends React.Component<Props, State> {
constructor(props: any) {
super(props);
this.state = {
error: '',
loadingPassword: true,
loadingSeed: true,
seed: '',
hasPassword: null,
passwordHash: '',
passwordValid: false,
};
this.copySeed = this.copySeed.bind(this);
this.getSeed = this.getSeed.bind(this);
this.confirmPassword = this.confirmPassword.bind(this);
this.checkHasPassword = this.checkHasPassword.bind(this);
this.onEnter = this.onEnter.bind(this);
}
public componentDidMount() {
setTimeout(() => $('#seed-input-password').focus(), 100);
}
public render() {
const i18n = window.i18n;
this.checkHasPassword();
this.getSeed().ignore();
const { onClose } = this.props;
const { hasPassword, passwordValid } = this.state;
const loading = this.state.loadingPassword || this.state.loadingSeed;
return (
<>
{!loading && (
<SessionModal
title={i18n('showSeed')}
onOk={() => null}
onClose={onClose}
>
<div className="spacer-sm" />
{hasPassword && !passwordValid ? (
<>{this.renderPasswordView()}</>
) : (
<>{this.renderSeedView()}</>
)}
</SessionModal>
)}
</>
);
}
private renderPasswordView() {
const maxPasswordLen = 64;
const error = this.state.error;
const i18n = window.i18n;
const { onClose } = this.props;
return (
<>
<p>{i18n('showSeedPasswordRequest')}</p>
<input
type="password"
id="seed-input-password"
placeholder={i18n('password')}
onKeyUp={this.onEnter}
maxLength={maxPasswordLen}
/>
{error && (
<>
<div className="spacer-xs" />
<div className="session-label danger">{error}</div>
</>
)}
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton
text={i18n('confirm')}
onClick={this.confirmPassword}
/>
<SessionButton text={i18n('cancel')} onClick={onClose} />
</div>
</>
);
}
private renderSeedView() {
const i18n = window.i18n;
const { onClose } = this.props;
return (
<>
<div className="session-modal__centered text-center">
<p className="session-modal__description">
{i18n('seedSavePromptMain')}
<br />
<span className="subtle">{i18n('seedSavePromptAlt')}</span>
</p>
<div className="spacer-xs" />
<i className="session-modal__text-highlight">{this.state.seed}</i>
</div>
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton text={i18n('ok')} onClick={onClose} />
<SessionButton
text={i18n('copySeed')}
onClick={() => {
this.copySeed(this.state.seed);
}}
/>
</div>
</>
);
}
private confirmPassword() {
const passwordHash = this.state.passwordHash;
const passwordValue = $('#seed-input-password').val();
const isPasswordValid = window.passwordUtil.matchesHash(
passwordValue,
passwordHash
);
if (!passwordValue) {
this.setState({
error: window.i18n('noGivenPassword'),
});
return false;
}
if (passwordHash && !isPasswordValid) {
this.setState({
error: window.i18n('invalidPassword'),
});
return false;
}
this.setState({
passwordValid: true,
error: '',
});
window.removeEventListener('keyup', this.onEnter);
return true;
}
private checkHasPassword() {
if (!this.state.loadingPassword) {
return;
}
const hashPromise = window.Signal.Data.getPasswordHash();
hashPromise.then((hash: any) => {
this.setState({
hasPassword: !!hash,
passwordHash: hash,
loadingPassword: false,
});
});
}
private async getSeed() {
if (this.state.seed) {
return false;
}
const manager = await window.getAccountManager();
const seed = manager.getCurrentMnemonic();
this.setState({
seed,
loadingSeed: false,
});
return true;
}
private copySeed(seed: string) {
window.clipboard.writeText(seed);
window.pushToast({
title: window.i18n('copiedMnemonic'),
type: 'success',
id: 'copySeedToast',
});
}
private onEnter(event: any) {
if (event.key === 'Enter') {
this.confirmPassword();
}
}
}