Modal additions incl. QR fixup and Seed View
parent
2caffa9289
commit
2ede557a74
@ -1,32 +0,0 @@
|
||||
/* global Whisper */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.SessionDropdownView = Whisper.View.extend({
|
||||
initialize(options) {
|
||||
this.props = {
|
||||
items: options.items,
|
||||
};
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
render() {
|
||||
this.dropdownView = new Whisper.ReactWrapperView({
|
||||
className: 'session-dropdown-wrapper',
|
||||
Component: window.Signal.Components.SessionDropdown,
|
||||
props: this.props,
|
||||
});
|
||||
|
||||
this.$el.append(this.dropdownView.el);
|
||||
},
|
||||
|
||||
openDropdown() {},
|
||||
|
||||
closeDropdown() {},
|
||||
});
|
||||
})();
|
@ -0,0 +1,198 @@
|
||||
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);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const i18n = window.i18n;
|
||||
const { onClose } = this.props;
|
||||
|
||||
const maxPasswordLen = 64;
|
||||
|
||||
this.checkHasPassword();
|
||||
this.getSeed();
|
||||
|
||||
const error = this.state.error;
|
||||
const hasPassword = this.state.hasPassword;
|
||||
const passwordValid = this.state.passwordValid;
|
||||
|
||||
const loading = this.state.loadingPassword || this.state.loadingSeed;
|
||||
|
||||
return (
|
||||
<SessionModal
|
||||
title={i18n('showSeed')}
|
||||
onOk={() => null}
|
||||
onClose={onClose}
|
||||
>
|
||||
{!loading && (
|
||||
<>
|
||||
<div className="spacer-sm" />
|
||||
|
||||
{hasPassword && !passwordValid ? (
|
||||
<div>
|
||||
<p>{i18n('showSeedPasswordRequest')}</p>
|
||||
<input
|
||||
type="password"
|
||||
id="seed-input-password"
|
||||
placeholder={i18n('password')}
|
||||
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>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="session-modal__centered text-center">
|
||||
<p className="session-modal__description">
|
||||
{i18n('seedSavePrompt')}
|
||||
</p>
|
||||
<div className="spacer-md" />
|
||||
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SessionModal>
|
||||
);
|
||||
}
|
||||
|
||||
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: '',
|
||||
});
|
||||
|
||||
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 this.state.seed;
|
||||
}
|
||||
|
||||
const manager = await window.getAccountManager();
|
||||
const seed = manager.getCurrentMnemonic();
|
||||
|
||||
this.setState({
|
||||
seed,
|
||||
loadingSeed: false,
|
||||
});
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
private copySeed(seed: string) {
|
||||
window.clipboard.writeText(seed);
|
||||
|
||||
window.pushToast({
|
||||
title: window.i18n('copiedMnemonic'),
|
||||
type: 'success',
|
||||
id: 'copySeedToast',
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue