on ded612b help sign in
bridge/src/lib/useKeyfileGenerator.js
139 lines 3.7 kB history raw
1import { useCallback, useMemo, useEffect, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import saveAs from 'file-saver';
4import ob from 'urbit-ob';
6import { usePointCache } from 'store/pointCache';
7import { useWallet } from 'store/wallet';
8import { usePointCursor } from 'store/pointCursor';
10import * as need from 'lib/need';
11import { generateCode } from 'lib/networkCode';
13import {
14 attemptNetworkSeedDerivation,
15 keysMatchChain,
16 deriveNetworkKeys,
17 compileNetworkingKey,
18} from './keys';
19import useCurrentPermissions from './useCurrentPermissions';
20import { convertToInt } from './convertToInt';
22export default function useKeyfileGenerator(manualNetworkSeed) {
23 const { urbitWallet, wallet, authMnemonic, authToken } = useWallet();
24 const { pointCursor } = usePointCursor();
25 const { getDetails } = usePointCache();
27 const [notice, setNotice] = useState('Deriving networking keys...');
28 const [downloaded, setDownloaded] = useState(false);
29 const [generating, setGenerating] = useState(true);
30 const [keyfile, setKeyfile] = useState(false);
32 const [code, setCode] = useState(false);
34 const _point = need.point(pointCursor);
35 const details = getDetails(_point);
37 const networkRevision = details.matchWith({
38 Just: ({ value }) => convertToInt(value.keyRevisionNumber, 10),
39 Nothing: () => 0,
40 });
41 const { isOwner, isManagementProxy } = useCurrentPermissions();
43 const hasNetworkingKeys = networkRevision > 0;
44 const available =
45 (isOwner || isManagementProxy) && hasNetworkingKeys && !!keyfile;
47 const generate = useCallback(async () => {
48 if (!hasNetworkingKeys) {
49 setGenerating(false);
50 setNotice('Networking keys not yet set.');
51 console.log(
52 `no networking keys available for revision ${networkRevision}`
53 );
54 return;
55 }
57 const _details = need.details(details);
59 const networkSeed = manualNetworkSeed
60 ? Just(manualNetworkSeed)
61 : await attemptNetworkSeedDerivation({
62 urbitWallet,
63 wallet,
64 authMnemonic,
65 details: _details,
66 authToken,
67 point: _point,
68 revision: networkRevision,
69 });
71 if (Nothing.hasInstance(networkSeed)) {
72 setGenerating(false);
73 setNotice(
74 'Custom or nondeterministic networking keys cannot be re-downloaded.'
75 );
76 console.log(`seed is nondeterminable for revision ${networkRevision}`);
77 return;
78 }
80 const _networkSeed = networkSeed.value;
82 const pair = deriveNetworkKeys(_networkSeed);
84 if (!keysMatchChain(pair, _details)) {
85 setGenerating(false);
86 setNotice('Derived networking keys do not match on-chain details.');
87 console.log(`keys do not match details for revision ${networkRevision}`);
88 return;
89 }
91 setNotice();
92 setCode(generateCode(pair));
93 setKeyfile(compileNetworkingKey(pair, _point, networkRevision));
94 setGenerating(false);
95 }, [
96 networkRevision,
97 hasNetworkingKeys,
98 manualNetworkSeed,
99 urbitWallet,
100 wallet,
101 authMnemonic,
102 setCode,
103 details,
104 _point,
105 authToken,
106 ]);
108 const filename = useMemo(() => {
109 return `${ob.patp(_point).slice(1)}-${networkRevision}.key`;
110 // TODO: ^ unifiy "remove tilde" calls
111 }, [_point, networkRevision]);
113 const download = useCallback(() => {
114 saveAs(
115 new Blob([keyfile], {
116 type: 'text/plain;charset=utf-8',
117 }),
118 filename
119 );
120 setDownloaded(true);
121 }, [filename, keyfile]);
123 useEffect(() => {
124 generate();
125 }, [generate]);
127 const values = {
128 generating,
129 available,
130 downloaded,
131 download,
132 filename,
133 notice,
134 keyfile,
135 code,
136 };
138 return { ...values, bind: values };