on f660f7b help sign in
bridge/src/views/GenKeyfile.js
142 lines 4.0 kB history raw
1import React from 'react';
2import * as need from '../lib/need';
4import { Button } from '../components/old/Base';
5import { 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';
17import View from 'components/View';
19class GenKeyfile extends React.Component {
20 constructor(props) {
21 super(props);
23 this.state = {
24 keyfile: '',
25 loaded: false,
26 };
27 }
29 getPointDetails() {
30 const point = need.point(this.props.pointCursor);
31 const pointDetails = need.fromPointCache(this.props.pointCache, 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 <View>
98 <H1>{'Generate keyfile'}</H1>
100 <P>{'Download a private key file for booting this point in Arvo.'}</P>
102 {keyfile === '' && !loaded && <P>{'Generating keyfile...'}</P>}
104 {keyfile === '' && loaded && (
105 <React.Fragment>
106 <P>
107 <b>Warning: </b>
108 {`No valid network seed detected. To generate a keyfile, you
109 must reset your networking keys, or try logging in with your
110 master ticket or management mnemonic.`}
111 </P>
113 <P>
114 {`If you've just reset your networking keys, you may need to wait for the transaction to go through. Check back shortly.`}
115 </P>
116 </React.Fragment>
117 )}
119 {keyfile !== '' && (
120 <React.Fragment>
121 <div className="pb-5 text-code keyfile">{keyfile}</div>
122 <Button
123 onClick={() => {
124 let blob = new Blob([keyfile], {
125 type: 'text/plain;charset=utf-8',
126 });
127 saveAs(blob, `${ob.patp(point).slice(1)}-${revision}.key`);
128 }}>
129 Download →
130 </Button>
131 </React.Fragment>
132 )}
133 </View>
134 );
135 }
138export default compose(
139 withWallet,
140 withPointCursor,
141 withPointCache
142)(GenKeyfile);