Mnemonic.tsx
1 import React, { PureComponent } from 'react'; 2 import { connect } from 'react-redux'; 3 import { mnemonicToSeed, validateMnemonic } from 'bip39'; 4 5 import { InsecureWalletName } from 'config'; 6 import translate, { translateRaw } from 'translations'; 7 import { formatMnemonic } from 'utils/formatters'; 8 import { AppState } from 'features/reducers'; 9 import { getSingleDPath, getPaths } from 'features/config'; 10 import { TogglablePassword } from 'components'; 11 import { Input } from 'components/ui'; 12 import DeterministicWalletsModal from './DeterministicWalletsModal'; 13 14 interface OwnProps { 15 onUnlock(param: any): void; 16 } 17 18 interface StateProps { 19 dPath: DPath; 20 dPaths: DPath[]; 21 } 22 23 type Props = OwnProps & StateProps; 24 25 interface State { 26 phrase: string; 27 formattedPhrase: string; 28 pass: string; 29 seed: string; 30 dPath: DPath; 31 } 32 33 class MnemonicDecryptClass extends PureComponent<Props, State> { 34 public state: State = { 35 phrase: '', 36 formattedPhrase: '', 37 pass: '', 38 seed: '', 39 dPath: this.props.dPath 40 }; 41 42 public UNSAFE_componentWillReceiveProps(nextProps: Props) { 43 if (this.props.dPath !== nextProps.dPath) { 44 this.setState({ dPath: nextProps.dPath }); 45 } 46 } 47 48 public render() { 49 const { phrase, formattedPhrase, seed, dPath, pass } = this.state; 50 const isValidMnemonic = validateMnemonic(formattedPhrase); 51 52 return ( 53 <React.Fragment> 54 <div id="selectedTypeKey"> 55 <div className="form-group"> 56 <TogglablePassword 57 value={phrase} 58 rows={4} 59 placeholder={translateRaw('X_MNEMONIC')} 60 isValid={isValidMnemonic} 61 isTextareaWhenVisible={true} 62 onChange={this.onMnemonicChange} 63 onEnter={isValidMnemonic ? this.onDWModalOpen : undefined} 64 /> 65 </div> 66 <div className="form-group"> 67 <p>{translate('ADD_LABEL_8')}</p> 68 <Input 69 isValid={true} 70 showValidAsPlain={true} 71 value={pass} 72 onChange={this.onPasswordChange} 73 placeholder={translateRaw('INPUT_PASSWORD_LABEL')} 74 type="password" 75 /> 76 </div> 77 <div className="form-group"> 78 <button 79 style={{ width: '100%' }} 80 onClick={this.onDWModalOpen} 81 className="btn btn-primary btn-lg" 82 disabled={!isValidMnemonic} 83 > 84 {translate('MNEMONIC_CHOOSE_ADDR')} 85 </button> 86 </div> 87 </div> 88 89 <DeterministicWalletsModal 90 isOpen={!!seed} 91 seed={seed} 92 dPath={dPath} 93 dPaths={this.props.dPaths} 94 onCancel={this.handleCancel} 95 onConfirmAddress={this.handleUnlock} 96 onPathChange={this.handlePathChange} 97 /> 98 </React.Fragment> 99 ); 100 } 101 102 public onPasswordChange = (e: React.FormEvent<HTMLInputElement>) => { 103 this.setState({ pass: e.currentTarget.value }); 104 }; 105 106 public onMnemonicChange = (e: React.FormEvent<HTMLTextAreaElement>) => { 107 const phrase = e.currentTarget.value; 108 const formattedPhrase = formatMnemonic(phrase); 109 110 this.setState({ 111 phrase, 112 formattedPhrase 113 }); 114 }; 115 116 public onDWModalOpen = () => { 117 const { formattedPhrase, pass } = this.state; 118 119 if (!validateMnemonic(formattedPhrase)) { 120 return; 121 } 122 123 try { 124 const seed = mnemonicToSeed(formattedPhrase, pass).toString('hex'); 125 this.setState({ seed }); 126 } catch (err) { 127 console.log(err); 128 } 129 }; 130 131 private handleCancel = () => { 132 this.setState({ seed: '' }); 133 }; 134 135 private handlePathChange = (dPath: DPath) => { 136 this.setState({ dPath }); 137 }; 138 139 private handleUnlock = (address: string, index: number) => { 140 const { formattedPhrase, pass, dPath } = this.state; 141 142 this.props.onUnlock({ 143 path: `${dPath.value}/${index}`, 144 pass, 145 phrase: formattedPhrase, 146 address 147 }); 148 149 this.setState({ 150 seed: '', 151 pass: '', 152 phrase: '', 153 formattedPhrase: '' 154 }); 155 }; 156 } 157 158 function mapStateToProps(state: AppState): StateProps { 159 return { 160 // Mnemonic dPath is guaranteed to always be provided 161 dPath: getSingleDPath(state, InsecureWalletName.MNEMONIC_PHRASE) as DPath, 162 dPaths: getPaths(state, InsecureWalletName.MNEMONIC_PHRASE) 163 }; 164 } 165 166 export const MnemonicDecrypt = connect(mapStateToProps)(MnemonicDecryptClass);