on 80f2d29 help sign in
bridge/src/views/Keystore.js
167 lines 4.7 kB history raw
1import { Just, Nothing } from 'folktale/maybe';
2import { Ok, Error } from 'folktale/result';
3import React from 'react';
4import * as keythereum from 'keythereum';
5import { Button, UploadButton } from '../components/old/Base';
6import { Input, InnerLabel, InputCaption } from '../components/old/Base';
7import { Row, Col, H1, H3, Warning } from '../components/old/Base';
9import { BRIDGE_ERROR } from '../lib/error';
10import { ROUTE_NAMES } from '../lib/routeNames';
11import { withHistory } from '../store/history';
12import { EthereumWallet } from '../lib/wallet';
13import { compose } from '../lib/lib';
14import { withWallet } from '../store/wallet';
16class Keystore extends React.Component {
17 constructor(props) {
18 super(props);
20 this.state = {
21 keystore: Nothing(), // Maybe<Result<String, String>>
22 password: '',
23 decryptionProblem: false,
24 };
26 this.handleKeystoreUpload = this.handleKeystoreUpload.bind(this);
27 this.handlePasswordInput = this.handlePasswordInput.bind(this);
28 this.constructWallet = this.constructWallet.bind(this);
29 }
31 handlePasswordInput(password) {
32 this.setState({ password });
33 }
35 constructWallet() {
36 const { setWallet } = this.props;
37 const { keystore, password } = this.state;
39 try {
40 const text = keystore.matchWith({
41 Nothing: _ => {
42 throw BRIDGE_ERROR.MISSING_KEYSTORE;
43 },
44 Just: ks =>
45 ks.value.matchWith({
46 Ok: result => result.value,
47 Error: _ => {
48 throw BRIDGE_ERROR.MISSING_KEYSTORE;
49 },
50 }),
51 });
53 const json = JSON.parse(text);
54 const privateKey = keythereum.recover(password, json);
56 const wallet = new EthereumWallet(privateKey);
57 this.setState({ decryptionProblem: false });
58 setWallet(Just(wallet));
59 } catch (err) {
60 this.setState({ decryptionProblem: true });
61 setWallet(Nothing());
62 }
63 }
65 handleKeystoreUpload = event => {
66 const file = event.files.item(0);
67 const reader = new FileReader();
69 reader.onload = e => {
70 const keystore = e.target.result;
71 this.setState({ keystore: Just(Ok(keystore)) });
72 };
74 const failure = _ => {
75 const message = 'There was a problem uploading your Keystore file';
76 this.setState({ keystore: Just(Error(message)) });
77 };
79 reader.onerror = failure;
80 reader.onabort = failure;
82 reader.readAsText(file);
83 };
85 render() {
86 const { history, wallet } = this.props;
87 const { keystore, password, decryptionProblem } = this.state;
89 const uploadButtonClass = keystore.matchWith({
90 Nothing: _ => 'bg-blue white',
91 Just: ks =>
92 ks.value.matchWith({
93 Ok: _ => 'bg-green white',
94 Error: _ => 'bg-yellow black',
95 }),
96 });
98 const decryptMessage =
99 decryptionProblem === false ? (
100 <div />
101 ) : (
102 <Warning className={'mt-8'}>
103 <H3 style={{ marginTop: 0, paddingTop: 0 }}>
104 {"Couldn't decrypt wallet."}
105 </H3>
106 {'You may have entered an incorrect password.'}
107 </Warning>
108 );
110 return (
111 <Row>
112 <Col className={'measure-md'}>
113 <H1 className={'mb-4'}>{'Upload Your Keystore File'}</H1>
114 <InputCaption>
115 {`Please upload your Ethereum keystore file. If your keystore
116 file is encrypted with a password, you'll also need to enter
117 that below.`}
118 </InputCaption>
120 <UploadButton
121 className={`btn ${uploadButtonClass} mt-10`}
122 onChange={this.handleKeystoreUpload}>
123 <div className={'flex-center-all fs-4 h-11 pointer'}>
124 {'Upload Keystore file'}
125 </div>
126 </UploadButton>
128 <Input
129 className="pt-8 mt-8"
130 prop-size="md"
131 prop-format="innerLabel"
132 type="password"
133 name="password"
134 onChange={this.handlePasswordInput}
135 value={password}
136 autocomplete="off"
137 autoFocus>
138 <InnerLabel>{'Password'}</InnerLabel>
139 </Input>
141 <Button
142 className={` mt-10`}
143 prop-size={'wide lg'}
144 disabled={Nothing.hasInstance(keystore)}
145 onClick={this.constructWallet}>
146 {'Decrypt'}
147 </Button>
149 {decryptMessage}
151 <Button
152 className={'mt-10'}
153 prop-size={'wide lg'}
154 disabled={Nothing.hasInstance(wallet)}
155 onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
156 {'Continue →'}
157 </Button>
158 </Col>
159 </Row>
160 );
161 }
164export default compose(
165 withHistory,
166 withWallet
167)(Keystore);