on fd7a195 help sign in
bridge/src/views/GenKeyfile.js
144 lines 4.0 kB history raw
1import React from 'react';
2import * as need from '../lib/need';
4import { Button } from '../components/old/Base';
5import { Row, Col, H1, P } from '../components/old/Base';
7import * as ob from 'urbit-ob';
8import * as kg from 'urbit-key-generation/dist';
9import saveAs from 'file-saver';
11import { attemptNetworkSeedDerivation, genKey } from '../lib/keys';
12import { addHexPrefix } from '../lib/wallet';
13import { compose } from '../lib/lib';
14import { withWallet } from '../store/wallet';
15import { withPointCursor } from '../store/pointCursor';
16import { withPointCache } from '../store/pointCache';
18class GenKeyfile extends React.Component {
19 constructor(props) {
20 super(props);
22 this.state = {
23 keyfile: '',
24 loaded: false,
25 };
26 }
28 getPointDetails() {
29 const point = need.pointCursor(this.props);
31 const pointDetails = need.fromPointCache(this.props, point);
33 // in case we did SetKeys earlier this session, make sure to generate the
34 // newer keyfile, rather than the one that will expire soon
35 const revision = this.props.networkRevision.matchWith({
36 Nothing: () => parseInt(pointDetails.keyRevisionNumber),
37 Just: p => p.value,
38 });
40 return {
41 point,
42 pointDetails,
43 revision,
44 };
45 }
47 async componentDidMount() {
48 const { point, pointDetails, revision } = this.getPointDetails();
49 let keyfile = '';
51 const hexRegExp = /[0-9A-Fa-f]{64}/g;
52 const networkSeed = await this.deriveSeed();
54 const keysmatch = this.checkKeysMatch(networkSeed, pointDetails);
55 const seedValid = hexRegExp.test(networkSeed);
57 if (keysmatch && seedValid) {
58 keyfile = genKey(networkSeed, point, revision);
59 }
61 this.setState({
62 keyfile: keyfile,
63 loaded: true,
64 });
65 }
67 checkKeysMatch(networkSeed, pointDetails) {
68 const crypub = pointDetails.encryptionKey;
69 const sgnpub = pointDetails.authenticationKey;
71 const { crypt, auth } = kg.deriveNetworkKeys(networkSeed);
73 const keysmatch =
74 crypub === addHexPrefix(crypt.public) &&
75 sgnpub === addHexPrefix(auth.public);
77 return keysmatch;
78 }
80 async deriveSeed() {
81 const next = false;
83 const seed = await attemptNetworkSeedDerivation(next, this.props);
85 // either return the derived seed, the cached seed, or empty string
86 return seed.matchWith({
87 Nothing: () => this.props.networkSeed.getOrElse(''),
88 Just: p => p.value,
89 });
90 }
92 render() {
93 const { point, revision } = this.getPointDetails();
94 const { keyfile, loaded } = this.state;
96 return (
97 <Row>
98 <Col className={'col-md-8'}>
99 <H1>{'Generate keyfile'}</H1>
101 <P>{'Download a private key file for booting this point in Arvo.'}</P>
103 {keyfile === '' && !loaded && <P>{'Generating keyfile...'}</P>}
105 {keyfile === '' && loaded && (
106 <React.Fragment>
107 <P>
108 <b>Warning: </b>
109 {`No valid network seed detected. To generate a keyfile, you
110 must reset your networking keys, or try logging in with your
111 master ticket or management mnemonic.`}
112 </P>
114 <P>
115 {`If you've just reset your networking keys, you may need to wait for the transaction to go through. Check back shortly.`}
116 </P>
117 </React.Fragment>
118 )}
120 {keyfile !== '' && (
121 <React.Fragment>
122 <div className="pb-5 text-code keyfile">{keyfile}</div>
123 <Button
124 onClick={() => {
125 let blob = new Blob([keyfile], {
126 type: 'text/plain;charset=utf-8',
127 });
128 saveAs(blob, `${ob.patp(point).slice(1)}-${revision}.key`);
129 }}>
130 Download →
131 </Button>
132 </React.Fragment>
133 )}
134 </Col>
135 </Row>
136 );
137 }
140export default compose(
141 withWallet,
142 withPointCursor,
143 withPointCache
144)(GenKeyfile);