Require phrase confirmation. (#5731)
* Require phrase confirmation. * Linting issues. * Fix dialog title. * Confirm a backup phrase. * Confirm recovery phrase on fist run as well.
This commit is contained in:
parent
06eb561af5
commit
5c3ea4ec29
@ -25,9 +25,16 @@ import styles from '../createAccount.css';
|
|||||||
@observer
|
@observer
|
||||||
export default class AccountDetails extends Component {
|
export default class AccountDetails extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
isConfirming: PropTypes.bool,
|
||||||
|
withRequiredBackup: PropTypes.bool,
|
||||||
createStore: PropTypes.object.isRequired
|
createStore: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static defaultPropTypes = {
|
||||||
|
isConfirming: false,
|
||||||
|
withRequiredBackup: false
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { address, description, name } = this.props.createStore;
|
const { address, description, name } = this.props.createStore;
|
||||||
|
|
||||||
@ -78,31 +85,103 @@ export default class AccountDetails extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPhrase () {
|
renderRequiredBackup () {
|
||||||
const { phrase } = this.props.createStore;
|
const { phraseBackedUp, phraseBackedUpError } = this.props.createStore;
|
||||||
|
|
||||||
if (!phrase) {
|
if (!this.props.withRequiredBackup) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<div>
|
||||||
allowCopy
|
<Input
|
||||||
hint={
|
error={ phraseBackedUpError }
|
||||||
<FormattedMessage
|
hint={
|
||||||
id='createAccount.accountDetails.phrase.hint'
|
<FormattedMessage
|
||||||
defaultMessage='the account recovery phrase'
|
id='createAccount.accountDetails.phrase.hint'
|
||||||
/>
|
defaultMessage='the account recovery phrase'
|
||||||
}
|
/>
|
||||||
label={
|
}
|
||||||
<FormattedMessage
|
label={
|
||||||
id='createAccount.accountDetails.phrase.label'
|
<FormattedMessage
|
||||||
defaultMessage='owner recovery phrase (keep private and secure, it allows full and unlimited access to the account)'
|
id='createAccount.accountDetails.phrase.backedUp'
|
||||||
/>
|
defaultMessage='Type "I have written down the phrase" below to confirm it is backed up.'
|
||||||
}
|
/>
|
||||||
readOnly
|
}
|
||||||
value={ phrase }
|
onChange={ this.onEditPhraseBackedUp }
|
||||||
/>
|
value={ phraseBackedUp }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderPhrase () {
|
||||||
|
const { isConfirming } = this.props;
|
||||||
|
const { isTest, phrase, backupPhraseError } = this.props.createStore;
|
||||||
|
|
||||||
|
const hint = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.accountDetails.phrase.hint'
|
||||||
|
defaultMessage='the account recovery phrase'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const label = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.accountDetails.phrase.label'
|
||||||
|
defaultMessage='owner recovery phrase'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isConfirming) {
|
||||||
|
if (!phrase) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
allowCopy
|
||||||
|
hint={ hint }
|
||||||
|
label={ label }
|
||||||
|
readOnly
|
||||||
|
value={ phrase }
|
||||||
|
/>
|
||||||
|
<div className={ styles.backupPhrase }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.accountDetails.phrase.backup'
|
||||||
|
defaultMessage='Please back up the recovery phrase now. Make sure to keep it private and secure, it allows full and unlimited access to the account.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{ this.renderRequiredBackup() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
allowPaste={ isTest }
|
||||||
|
error={ backupPhraseError }
|
||||||
|
hint={ hint }
|
||||||
|
label={ label }
|
||||||
|
onChange={ this.onEditPhrase }
|
||||||
|
value={ phrase }
|
||||||
|
/>
|
||||||
|
<div className={ styles.backupPhrase }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.accountDetails.phrase.backupConfirm'
|
||||||
|
defaultMessage='Type your recovery phrase now.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditPhraseBackedUp = (ev) => {
|
||||||
|
this.props.createStore.setPhraseBackedUp(ev.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditPhrase = (ev) => {
|
||||||
|
this.props.createStore.setPhrase(ev.target.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,3 +131,8 @@
|
|||||||
padding: 0 4em 1.5em 4em;
|
padding: 0 4em 1.5em 4em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.backupPhrase {
|
||||||
|
line-height: 1.618em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@ import NewImport from './NewImport';
|
|||||||
import NewQr from './NewQr';
|
import NewQr from './NewQr';
|
||||||
import RawKey from './RawKey';
|
import RawKey from './RawKey';
|
||||||
import RecoveryPhrase from './RecoveryPhrase';
|
import RecoveryPhrase from './RecoveryPhrase';
|
||||||
import Store, { STAGE_CREATE, STAGE_INFO, STAGE_SELECT_TYPE } from './store';
|
import Store, { STAGE_CREATE, STAGE_INFO, STAGE_SELECT_TYPE, STAGE_CONFIRM_BACKUP } from './store';
|
||||||
import TypeIcon from './TypeIcon';
|
import TypeIcon from './TypeIcon';
|
||||||
import print from './print';
|
import print from './print';
|
||||||
import recoveryPage from './recoveryPage.ejs';
|
import recoveryPage from './recoveryPage.ejs';
|
||||||
@ -61,6 +61,12 @@ const TITLES = {
|
|||||||
defaultMessage='account information'
|
defaultMessage='account information'
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
backup: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.title.backupPhrase'
|
||||||
|
defaultMessage='confirm recovery phrase'
|
||||||
|
/>
|
||||||
|
),
|
||||||
import: (
|
import: (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='createAccount.title.importAccount'
|
id='createAccount.title.importAccount'
|
||||||
@ -80,7 +86,7 @@ const TITLES = {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
const STAGE_NAMES = [TITLES.type, TITLES.create, TITLES.info];
|
const STAGE_NAMES = [TITLES.type, TITLES.create, TITLES.info, TITLES.backup];
|
||||||
const STAGE_IMPORT = [TITLES.type, TITLES.import, TITLES.info];
|
const STAGE_IMPORT = [TITLES.type, TITLES.import, TITLES.info];
|
||||||
const STAGE_RESTORE = [TITLES.restore, TITLES.info];
|
const STAGE_RESTORE = [TITLES.restore, TITLES.info];
|
||||||
const STAGE_QR = [TITLES.type, TITLES.qr, TITLES.info];
|
const STAGE_QR = [TITLES.type, TITLES.qr, TITLES.info];
|
||||||
@ -213,14 +219,25 @@ class CreateAccount extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AccountDetails createStore={ this.createStore } />
|
<AccountDetails
|
||||||
|
createStore={ this.createStore }
|
||||||
|
withRequiredBackup={ createType === 'fromNew' }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
case STAGE_CONFIRM_BACKUP:
|
||||||
|
return (
|
||||||
|
<AccountDetails
|
||||||
|
createStore={ this.createStore }
|
||||||
|
isConfirming
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDialogActions () {
|
renderDialogActions () {
|
||||||
const { restore } = this.props;
|
const { restore } = this.props;
|
||||||
const { createType, canCreate, isBusy, stage } = this.createStore;
|
const { createType, canCreate, isBusy, stage, phraseBackedUpError } = this.createStore;
|
||||||
|
|
||||||
const cancelBtn = (
|
const cancelBtn = (
|
||||||
<Button
|
<Button
|
||||||
@ -281,8 +298,8 @@ class CreateAccount extends Component {
|
|||||||
createType === 'fromNew'
|
createType === 'fromNew'
|
||||||
? (
|
? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='createAccount.button.create'
|
id='createAccount.button.next'
|
||||||
defaultMessage='Create'
|
defaultMessage='Next'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
@ -292,7 +309,7 @@ class CreateAccount extends Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={ this.onCreate }
|
onClick={ createType === 'fromNew' ? this.createStore.nextStage : this.onCreate }
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -314,6 +331,7 @@ class CreateAccount extends Component {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
<Button
|
<Button
|
||||||
|
disabled={ createType === 'fromNew' && !!phraseBackedUpError }
|
||||||
icon={ <DoneIcon /> }
|
icon={ <DoneIcon /> }
|
||||||
key='done'
|
key='done'
|
||||||
label={
|
label={
|
||||||
@ -322,12 +340,55 @@ class CreateAccount extends Component {
|
|||||||
defaultMessage='Done'
|
defaultMessage='Done'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onClick={ this.onClose }
|
onClick={ createType === 'fromNew' ? this.onConfirmPhraseBackup : this.onClose }
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
|
||||||
|
case STAGE_CONFIRM_BACKUP:
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
icon={ <DoneIcon /> }
|
||||||
|
key='done'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.button.create'
|
||||||
|
defaultMessage='Create'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onCreateNew }
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onConfirmPhraseBackup = () => {
|
||||||
|
this.createStore.clearPhrase();
|
||||||
|
this.createStore.nextStage();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreateNew = () => {
|
||||||
|
this.createStore.setBusy(true);
|
||||||
|
this.createStore.computeBackupPhraseAddress()
|
||||||
|
.then(err => {
|
||||||
|
if (err) {
|
||||||
|
this.createStore.setBusy(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createStore.createAccount(this.vaultStore)
|
||||||
|
.then(() => {
|
||||||
|
this.createStore.clearPhrase();
|
||||||
|
this.createStore.setBusy(false);
|
||||||
|
this.props.onUpdate && this.props.onUpdate();
|
||||||
|
this.onClose();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.createStore.setBusy(false);
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onCreate = () => {
|
onCreate = () => {
|
||||||
return this.createStore
|
return this.createStore
|
||||||
.createAccount(this.vaultStore)
|
.createAccount(this.vaultStore)
|
||||||
@ -341,6 +402,7 @@ class CreateAccount extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClose = () => {
|
onClose = () => {
|
||||||
|
this.createStore.clearPhrase();
|
||||||
this.props.onClose && this.props.onClose();
|
this.props.onClose && this.props.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,20 @@ export default {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
||||||
|
noMatchBackupPhrase: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='errors.noMatchBackupPhrase'
|
||||||
|
defaultMessage='the supplied recovery phrase does not match'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
|
||||||
|
noMatchPhraseBackedUp: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='errors.noMatchPhraseBackedUp'
|
||||||
|
defaultMessage='type "I have written down the phrase"'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
|
||||||
noName: (
|
noName: (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='errors.noName'
|
id='errors.noName'
|
||||||
@ -59,4 +73,5 @@ export default {
|
|||||||
defaultMessage='the raw key needs to be hex, 64 characters in length and contain the prefix "0x"'
|
defaultMessage='the raw key needs to be hex, 64 characters in length and contain the prefix "0x"'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -24,6 +24,7 @@ const FAKEPATH = 'C:\\fakepath\\';
|
|||||||
const STAGE_SELECT_TYPE = 0;
|
const STAGE_SELECT_TYPE = 0;
|
||||||
const STAGE_CREATE = 1;
|
const STAGE_CREATE = 1;
|
||||||
const STAGE_INFO = 2;
|
const STAGE_INFO = 2;
|
||||||
|
const STAGE_CONFIRM_BACKUP = 3;
|
||||||
|
|
||||||
export default class Store {
|
export default class Store {
|
||||||
@observable accounts = null;
|
@observable accounts = null;
|
||||||
@ -41,6 +42,8 @@ export default class Store {
|
|||||||
@observable passwordHint = '';
|
@observable passwordHint = '';
|
||||||
@observable passwordRepeat = '';
|
@observable passwordRepeat = '';
|
||||||
@observable phrase = '';
|
@observable phrase = '';
|
||||||
|
@observable backupPhraseAddress = null;
|
||||||
|
@observable phraseBackedUp = '';
|
||||||
@observable qrAddress = null;
|
@observable qrAddress = null;
|
||||||
@observable rawKey = '';
|
@observable rawKey = '';
|
||||||
@observable rawKeyError = ERRORS.nokey;
|
@observable rawKeyError = ERRORS.nokey;
|
||||||
@ -104,17 +107,39 @@ export default class Store {
|
|||||||
: ERRORS.noMatchPassword;
|
: ERRORS.noMatchPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@computed get backupPhraseError () {
|
||||||
|
return !this.backupPhraseAddress || this.address === this.backupPhraseAddress
|
||||||
|
? null
|
||||||
|
: ERRORS.noMatchBackupPhrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get phraseBackedUpError () {
|
||||||
|
return this.phraseBackedUp === 'I have written down the phrase'
|
||||||
|
? null
|
||||||
|
: ERRORS.noMatchPhraseBackedUp;
|
||||||
|
}
|
||||||
|
|
||||||
@computed get qrAddressValid () {
|
@computed get qrAddressValid () {
|
||||||
console.log('qrValid', this.qrAddress, this._api.util.isAddressValid(this.qrAddress));
|
console.log('qrValid', this.qrAddress, this._api.util.isAddressValid(this.qrAddress));
|
||||||
return this._api.util.isAddressValid(this.qrAddress);
|
return this._api.util.isAddressValid(this.qrAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action clearPhrase = () => {
|
||||||
|
transaction(() => {
|
||||||
|
this.phrase = '';
|
||||||
|
this.phraseBackedUp = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@action clearErrors = () => {
|
@action clearErrors = () => {
|
||||||
transaction(() => {
|
transaction(() => {
|
||||||
|
this.address = '';
|
||||||
this.description = '';
|
this.description = '';
|
||||||
this.password = '';
|
this.password = '';
|
||||||
this.passwordRepeat = '';
|
this.passwordRepeat = '';
|
||||||
this.phrase = '';
|
this.phrase = '';
|
||||||
|
this.backupPhraseAddress = null;
|
||||||
|
this.phraseBackedUp = '';
|
||||||
this.name = '';
|
this.name = '';
|
||||||
this.nameError = ERRORS.noName;
|
this.nameError = ERRORS.noName;
|
||||||
this.qrAddress = null;
|
this.qrAddress = null;
|
||||||
@ -192,6 +217,26 @@ export default class Store {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action setBackupPhraseAddress = (address) => {
|
||||||
|
this.backupPhraseAddress = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action computeBackupPhraseAddress = () => {
|
||||||
|
return this._api.parity.phraseToAddress(this.phrase)
|
||||||
|
.then(address => {
|
||||||
|
this.setBackupPhraseAddress(address);
|
||||||
|
return address !== this.address;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('createAccount', error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setPhraseBackedUp = (backedUp) => {
|
||||||
|
this.phraseBackedUp = backedUp;
|
||||||
|
}
|
||||||
|
|
||||||
@action setPassword = (password) => {
|
@action setPassword = (password) => {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
@ -217,6 +262,7 @@ export default class Store {
|
|||||||
.filter((part) => part.length);
|
.filter((part) => part.length);
|
||||||
|
|
||||||
this.phrase = phraseParts.join(' ');
|
this.phrase = phraseParts.join(' ');
|
||||||
|
this.backupPhraseAddress = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action setRawKey = (rawKey) => {
|
@action setRawKey = (rawKey) => {
|
||||||
@ -460,7 +506,8 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
STAGE_CREATE,
|
|
||||||
STAGE_INFO,
|
STAGE_INFO,
|
||||||
|
STAGE_CONFIRM_BACKUP,
|
||||||
|
STAGE_CREATE,
|
||||||
STAGE_SELECT_TYPE
|
STAGE_SELECT_TYPE
|
||||||
};
|
};
|
||||||
|
@ -52,6 +52,10 @@ const STAGE_NAMES = [
|
|||||||
id='firstRun.title.recovery'
|
id='firstRun.title.recovery'
|
||||||
defaultMessage='recovery'
|
defaultMessage='recovery'
|
||||||
/>,
|
/>,
|
||||||
|
<FormattedMessage
|
||||||
|
id='firstRun.title.confirmation'
|
||||||
|
defaultMessage='confirmation'
|
||||||
|
/>,
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='firstRun.title.completed'
|
id='firstRun.title.completed'
|
||||||
defaultMessage='completed'
|
defaultMessage='completed'
|
||||||
@ -129,9 +133,19 @@ class FirstRun extends Component {
|
|||||||
);
|
);
|
||||||
case 3:
|
case 3:
|
||||||
return (
|
return (
|
||||||
<AccountDetails createStore={ this.createStore } />
|
<AccountDetails
|
||||||
|
createStore={ this.createStore }
|
||||||
|
withRequiredBackup
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
case 4:
|
case 4:
|
||||||
|
return (
|
||||||
|
<AccountDetails
|
||||||
|
createStore={ this.createStore }
|
||||||
|
isConfirming
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case 5:
|
||||||
return (
|
return (
|
||||||
<Completed />
|
<Completed />
|
||||||
);
|
);
|
||||||
@ -141,7 +155,7 @@ class FirstRun extends Component {
|
|||||||
renderDialogActions () {
|
renderDialogActions () {
|
||||||
const { hasAccounts } = this.props;
|
const { hasAccounts } = this.props;
|
||||||
const { stage, hasAcceptedTnc } = this.state;
|
const { stage, hasAcceptedTnc } = this.state;
|
||||||
const { canCreate } = this.createStore;
|
const { canCreate, phraseBackedUpError } = this.createStore;
|
||||||
|
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -169,15 +183,10 @@ class FirstRun extends Component {
|
|||||||
const buttons = [
|
const buttons = [
|
||||||
<Button
|
<Button
|
||||||
disabled={ !canCreate }
|
disabled={ !canCreate }
|
||||||
icon={ <CheckIcon /> }
|
icon={ <NextIcon /> }
|
||||||
key='create'
|
key='next'
|
||||||
label={
|
label={ BUTTON_LABEL_NEXT }
|
||||||
<FormattedMessage
|
onClick={ this.onNext }
|
||||||
id='firstRun.button.create'
|
|
||||||
defaultMessage='Create'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onClick={ this.onCreate }
|
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -212,14 +221,30 @@ class FirstRun extends Component {
|
|||||||
onClick={ this.printPhrase }
|
onClick={ this.printPhrase }
|
||||||
/>,
|
/>,
|
||||||
<Button
|
<Button
|
||||||
|
disabled={ !!phraseBackedUpError }
|
||||||
icon={ <NextIcon /> }
|
icon={ <NextIcon /> }
|
||||||
key='next'
|
key='next'
|
||||||
label={ BUTTON_LABEL_NEXT }
|
label={ BUTTON_LABEL_NEXT }
|
||||||
onClick={ this.onNext }
|
onClick={ this.onConfirmPhraseBackup }
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
icon={ <CheckIcon /> }
|
||||||
|
key='create'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='firstRun.button.create'
|
||||||
|
defaultMessage='Create'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onCreate }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 5:
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
icon={ <DoneIcon /> }
|
icon={ <DoneIcon /> }
|
||||||
@ -244,6 +269,11 @@ class FirstRun extends Component {
|
|||||||
}, onClose);
|
}, onClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onConfirmPhraseBackup = () => {
|
||||||
|
this.createStore.clearPhrase();
|
||||||
|
this.onNext();
|
||||||
|
}
|
||||||
|
|
||||||
onNext = () => {
|
onNext = () => {
|
||||||
const { stage } = this.state;
|
const { stage } = this.state;
|
||||||
|
|
||||||
@ -261,11 +291,19 @@ class FirstRun extends Component {
|
|||||||
onCreate = () => {
|
onCreate = () => {
|
||||||
this.createStore.setBusy(true);
|
this.createStore.setBusy(true);
|
||||||
|
|
||||||
return this.createStore
|
this.createStore.computeBackupPhraseAddress()
|
||||||
.createAccount()
|
.then(err => {
|
||||||
.then(() => {
|
if (err) {
|
||||||
this.onNext();
|
this.createStore.setBusy(false);
|
||||||
this.createStore.setBusy(false);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createStore.createAccount()
|
||||||
|
.then(() => {
|
||||||
|
this.createStore.clearPhrase();
|
||||||
|
this.createStore.setBusy(false);
|
||||||
|
this.onNext();
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.createStore.setBusy(false);
|
this.createStore.setBusy(false);
|
||||||
|
@ -57,6 +57,7 @@ export default class Input extends Component {
|
|||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
PropTypes.bool
|
PropTypes.bool
|
||||||
]),
|
]),
|
||||||
|
allowPaste: PropTypes.bool,
|
||||||
autoFocus: PropTypes.bool,
|
autoFocus: PropTypes.bool,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
@ -97,6 +98,7 @@ export default class Input extends Component {
|
|||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
allowCopy: false,
|
allowCopy: false,
|
||||||
|
allowPaste: true,
|
||||||
escape: 'initial',
|
escape: 'initial',
|
||||||
hideUnderline: false,
|
hideUnderline: false,
|
||||||
onBlur: noop,
|
onBlur: noop,
|
||||||
@ -221,6 +223,12 @@ export default class Input extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onChange = (event, value) => {
|
onChange = (event, value) => {
|
||||||
|
if (!this.props.allowPaste) {
|
||||||
|
if (value.length - this.state.value.length > 8) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event.persist();
|
event.persist();
|
||||||
|
|
||||||
this.setValue(value, () => {
|
this.setValue(value, () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user