on c9ab246 help sign in
bridge/src/lib/useKeyfileGenerator.js
126 lines 3.5 kB history raw
1import { useCallback, 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 } = 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 = need.details(getDetails(_point));
37 const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
38 const { isOwner, isManagementProxy } = useCurrentPermissions();
40 const hasNetworkingKeys = networkRevision > 0;
41 const available =
42 (isOwner || isManagementProxy) && hasNetworkingKeys && !!keyfile;
44 const generate = useCallback(async () => {
45 if (!hasNetworkingKeys) {
46 setGenerating(false);
47 setNotice('Networking keys not yet set.');
48 console.log(
49 `no networking keys available for revision ${networkRevision}`
50 );
51 return;
52 }
54 const networkSeed = manualNetworkSeed
55 ? Just(manualNetworkSeed)
56 : await attemptNetworkSeedDerivation({
57 urbitWallet,
58 wallet,
59 authMnemonic,
60 details: _details,
61 revision: networkRevision,
62 });
64 if (Nothing.hasInstance(networkSeed)) {
65 setGenerating(false);
66 setNotice(
67 'Custom or nondeterministic networking keys cannot be re-downloaded.'
68 );
69 console.log(`seed is nondeterminable for revision ${networkRevision}`);
70 return;
71 }
73 const _networkSeed = networkSeed.value;
75 const pair = deriveNetworkKeys(_networkSeed);
77 setCode(generateCode(pair));
79 if (!keysMatchChain(pair, _details)) {
80 setGenerating(false);
81 setNotice('Derived networking keys do not match on-chain details.');
82 console.log(`keys do not match details for revision ${networkRevision}`);
83 return;
84 }
86 setNotice();
87 setKeyfile(compileNetworkingKey(pair, _point, networkRevision));
88 setGenerating(false);
89 }, [
90 networkRevision,
91 hasNetworkingKeys,
92 manualNetworkSeed,
93 urbitWallet,
94 wallet,
95 authMnemonic,
96 setCode,
97 _details,
98 _point,
99 ]);
101 const download = useCallback(() => {
102 saveAs(
103 new Blob([keyfile], {
104 type: 'text/plain;charset=utf-8',
105 }),
106 `${ob.patp(_point).slice(1)}-${networkRevision}.key`
107 // TODO: ^ unifiy "remove tilde" calls
108 );
109 setDownloaded(true);
110 }, [_point, keyfile, networkRevision]);
112 useEffect(() => {
113 generate();
114 }, [generate]);
116 const values = {
117 generating,
118 available,
119 downloaded,
120 download,
121 notice,
122 code,
123 };
125 return { ...values, bind: values };