on 5f71b99 help sign in
bridge/src/views/GenKeyfile.js
173 lines 4.3 kB history raw
1import React from 'react'
2import Maybe from 'folktale/maybe'
4import { Button } from '../components/Base'
5import { RequiredInput, InnerLabel } from '../components/Base'
6import { Row, Col, H1, P } from '../components/Base'
7import { Code } from '../components/Base'
9import * as ob from 'urbit-ob'
10import * as kg from '../../node_modules/urbit-key-generation/dist/index'
11import saveAs from 'file-saver'
13import { attemptSeedDerivation, genKey } from '../lib/keys'
14import { BRIDGE_ERROR } from '../lib/error'
15import {
16 addHexPrefix
17 } from '../lib/wallet'
19class GenKeyfile extends React.Component {
20 constructor(props) {
21 super(props)
23 this.state = {
24 keyfile: '',
25 networkSeed: ''
26 }
28 this.handleNetworkSeedInput = this.handleNetworkSeedInput.bind(this)
29 this.handleKeyfileChange = this.handleKeyfileChange.bind(this)
30 }
32 componentDidMount() {
33 this.deriveSeed()
34 }
36 async deriveSeed() {
37 const next = false
38 let seed = await attemptSeedDerivation(next, this.props)
40 if (seed.getOrElse('') === '' && this.props.networkSeedCache) {
41 seed = Maybe.Just(this.props.networkSeedCache)
42 }
44 this.setState({
45 networkSeed: seed.getOrElse('')
46 })
47 }
49 handleNetworkSeedInput = (networkSeed) => {
50 this.setState({ networkSeed })
51 }
53 handleKeyfileChange = (keyfile) => {
54 this.setState({ keyfile })
55 }
57 render() {
58 const { pointCache } = this.props
59 const { pointCursor } = this.props
61 const { keyfile, networkSeed } = this.state
63 const point = pointCursor.matchWith({
64 Just: (pt) => pt.value,
65 Nothing: () => {
66 throw BRIDGE_ERROR.MISSING_POINT
67 }
68 })
70 const pointDetails =
71 point in pointCache
72 ? pointCache[point]
73 : (() => { throw BRIDGE_ERROR.MISSING_POINT })()
75 const revision = parseInt(pointDetails.keyRevisionNumber)
77 const crypub = pointDetails.encryptionKey
78 const sgnpub = pointDetails.authenticationKey
80 const { crypt, auth } = kg.deriveNetworkKeys(networkSeed)
82 const keysmatch =
83 crypub === addHexPrefix(crypt.public)
84 && sgnpub === addHexPrefix(auth.public)
86 const warning =
87 keyfile !== '' && keysmatch === false
88 ? <Row>
89 <Col>
90 <b>{ 'WARNING' }</b>{ ": derived key doesn't match Azimuth keys!" }
91 </Col>
92 </Row>
93 : <div />
95 const hexRegExp = /[0-9A-Fa-f]{64}/g
97 const download =
98 keyfile !== ''
99 ? <Button
100 onClick={
101 () => {
102 let blob = new Blob([keyfile], {type:"text/plain;charset=utf-8"});
103 saveAs(blob, `${ob.patp(point).slice(1)}-${revision}.key`)
104 }
105 }>
106 Download →
107 </Button>
108 : ''
110 return (
111 <Row>
112 <Col className={'col-md-8'}>
113 <H1>{ 'Generate keyfile' }</H1>
115 <P>
116 { "Generate a private key file for booting this point in Arvo." }
117 </P>
119 <P>
120 {
121 `Enter a network seed below for generating your key file. Your
122 network seed must be a string of 64 characters (containing 0-9, A-Z, a-z)`
123 }
124 </P>
125 <P>
126 {
127 `If you've authenticated with either a master ticket or a
128 management proxy mnemonic, a seed will be generated for you
129 automatically.`
130 }
131 </P>
133 <RequiredInput
134 className='mono'
135 prop-size='lg'
136 prop-format='innerLabel'
137 autoFocus
138 value={ networkSeed }
139 onChange={ this.handleNetworkSeedInput }>
140 <InnerLabel>{ 'Network seed' }</InnerLabel>
141 </RequiredInput>
143 <Button
144 className={'mt-8'}
145 color={'blue'}
146 onClick={
147 () => {
148 if (hexRegExp.test(networkSeed)) {
149 const keyfile = genKey(networkSeed, point, revision)
150 this.setState({ keyfile })
151 }
152 }
153 }
154 >
155 { 'Generate →' }
156 </Button>
158 <Code>
159 { keyfile }
160 </Code>
162 { warning }
164 { download }
166 </Col>
167 </Row>
168 )
169 }
173export default GenKeyfile