// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity. // // SPDX-License-Identifier: BSD-3-Clause import React, { Component } from 'react'; import { addressShort, Card, Form as FetherForm } from 'fether-ui'; import { inject, observer } from 'mobx-react'; import RequireHealthOverlay from '../../../RequireHealthOverlay'; import Scanner from '../../../Scanner'; import withAccountsInfo from '../../../utils/withAccountsInfo'; import getBip39Wordlist from '../../../stores/utils/getBip39Wordlist'; import getParityWordlist from '../../../stores/utils/getParityWordlist'; const BIP39_WORDLIST = getBip39Wordlist(); const PARITY_WORDLIST = getParityWordlist(); @withAccountsInfo @inject('createAccountStore') @observer class AccountImportOptions extends Component { state = { error: '', invalidWords: new Set(), isLoading: false, phrase: '', importingFromSigner: false }; handleNextStep = async () => { const { history, location: { pathname } } = this.props; const currentStep = pathname.slice(-1); history.push(`/accounts/new/${+currentStep + 1}`); }; handlePhraseChange = ({ target: { value: phrase } }) => { const { invalidWords } = this.state; const words = phrase.split(' '); const lastVal = words.slice(-1); const isWordEnded = lastVal.join() === ''; if (isWordEnded) { for (let i = 0; i < words.length; i++) { let word = words[i]; if ( word && !BIP39_WORDLIST.has(word.toLowerCase()) && !PARITY_WORDLIST.has(word.toLowerCase()) ) { invalidWords.add(word); this.setState({ invalidWords }); } } invalidWords.forEach(invalidWord => { if (!words.includes(invalidWord)) { invalidWords.delete(invalidWord); } }); } if (invalidWords && invalidWords.size) { // Guide them to contact Fether Riot let error = ( {`${Array.from(invalidWords).join( ', ' )} is not a valid BIP39 or Parity word. If you wish to recover your account with a self-generated phrase, please`} ); this.setState({ error }); } else { this.setState({ error: null }); } this.setState({ phrase: phrase.toLowerCase() }); }; handleSubmitPhrase = async () => { const phrase = this.state.phrase.trim(); const { createAccountStore, createAccountStore: { setPhrase } } = this.props; this.setState({ isLoading: true, phrase }); try { await setPhrase(phrase); if (this.hasExistingAddressForImport(createAccountStore.address)) { return; } this.handleNextStep(); } catch (error) { this.setState({ isLoading: false, error: 'The passphrase was not recognized. Please verify that you entered your passphrase correctly.' }); console.error(error); } }; handleChangeFile = async jsonString => { const { createAccountStore, createAccountStore: { setJsonString } } = this.props; this.setState({ isLoading: true }); try { await setJsonString(jsonString); if (this.hasExistingAddressForImport(createAccountStore.address)) { return; } this.handleNextStep(); } catch (error) { this.setState({ isLoading: false, error: 'Invalid file. Please check this is your actual Parity backup JSON keyfile and try again.' }); console.error(error); } }; handleSignerImported = async ({ address, chainId: chainIdString }) => { const { createAccountStore: { importFromSigner } } = this.props; if (!address || !chainIdString) { this.setState({ error: 'Invalid QR code.' }); return; } const chainId = parseInt(chainIdString); if (this.hasExistingAddressForImport(address, chainId)) { return; } await importFromSigner({ address, chainId }); this.handleNextStep(); }; handleSignerImport = () => { this.setState({ importingFromSigner: true }); }; hasExistingAddressForImport = (addressForImport, chainId) => { const { accountsInfo } = this.props; const isExistingAddress = Object.keys(accountsInfo).some( key => key.toLowerCase() === addressForImport.toLowerCase() && (!accountsInfo[key].chainId || !chainId || accountsInfo[key].chainId === chainId) ); if (isExistingAddress) { this.setState({ isLoading: false, error: `Account ${addressShort(addressForImport)} already listed` }); } return isExistingAddress; }; render () { const { history, location: { pathname } } = this.props; const { error, importingFromSigner, phrase } = this.state; const currentStep = pathname.slice(-1); const jsonCard = (

Recover from JSON Keyfile

); const signerCard = (

Recover from Parity Signer

{importingFromSigner ? ( ) : ( )}
); const phraseCard = (

Recover from Seed Phrase

{this.renderButton()}
); const spacer =
; return (
{!importingFromSigner && jsonCard} {spacer} {signerCard} {spacer} {!importingFromSigner && phraseCard}

{error}

); } renderButton = () => { const { isLoading, json, phrase } = this.state; // If we are importing an existing account, the button goes to the next step return ( ); }; } export default AccountImportOptions;