on 0174dd5 help sign in
bridge/src/lib/useKeyfileGenerator.ts
161 lines 4.2 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 compileNetworkKey,
18} from './keys';
19import useCurrentPermissions from './useCurrentPermissions';
20import { convertToInt } from './convertToInt';
21import { stripSigPrefix } from 'form/formatters';
23// overrideable defaults:
24// seed - derived from wallet, mnemonic, or token (if posisble)
25// point - the current pointCursor
26interface useKeyfileGeneratorArgs {
27 seed?: string;
28 point?: number;
31/**
32 * @deprecated
33 * Use `useMultikeyFileGenerator` instead
34 */
35export default function useKeyfileGenerator({
36 seed,
37 point,
38}: useKeyfileGeneratorArgs) {
39 const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
40 const { pointCursor }: any = usePointCursor();
41 const { syncDetails, getDetails }: any = usePointCache();
43 const [notice, setNotice] = useState('Deriving networking keys...');
44 const [downloaded, setDownloaded] = useState(false);
45 const [generating, setGenerating] = useState(true);
46 const [keyfile, setKeyfile] = useState<boolean | string>(false);
47 const [code, setCode] = useState(false);
49 const _point = point || need.point(pointCursor);
50 useEffect(() => {
51 syncDetails(_point);
52 }, [_point, syncDetails]);
54 const details = getDetails(_point);
56 const networkRevision = details.matchWith({
57 Just: ({ value }) => convertToInt(value.keyRevisionNumber, 10),
58 Nothing: () => 0,
59 });
60 const { isOwner, isManagementProxy } = useCurrentPermissions();
62 const hasNetworkKeys = networkRevision > 0;
63 const available =
64 (isOwner || isManagementProxy) && hasNetworkKeys && !!keyfile;
66 const generate = useCallback(async () => {
67 if (!hasNetworkKeys) {
68 setGenerating(false);
69 setNotice('Network keys not yet set.');
70 console.log(
71 `no networking keys available for revision ${networkRevision}`
72 );
73 return;
74 }
76 const _details = need.details(details);
78 const networkSeed = seed
79 ? Just(seed)
80 : await attemptNetworkSeedDerivation({
81 urbitWallet,
82 wallet,
83 authMnemonic,
84 details: _details,
85 authToken,
86 point: _point,
87 revision: networkRevision,
88 });
90 if (Nothing.hasInstance(networkSeed)) {
91 setGenerating(false);
92 setNotice(
93 'Custom or nondeterministic networking keys cannot be re-downloaded.'
94 );
95 console.log(`seed is nondeterminable for revision ${networkRevision}`);
96 return;
97 }
99 const _networkSeed = networkSeed.value;
101 const pair = deriveNetworkKeys(_networkSeed);
103 if (!keysMatchChain(pair, _details)) {
104 setGenerating(false);
105 setNotice('Derived networking keys do not match on-chain details.');
106 console.log(`keys do not match details for revision ${networkRevision}`);
107 return;
108 }
110 setNotice('');
111 setCode(generateCode(pair));
112 setKeyfile(compileNetworkKey(pair, _point, networkRevision));
113 setGenerating(false);
114 }, [
115 networkRevision,
116 hasNetworkKeys,
117 seed,
118 urbitWallet,
119 wallet,
120 authMnemonic,
121 setCode,
122 details,
123 _point,
124 authToken,
125 ]);
127 const filename = useMemo(() => {
128 return `${stripSigPrefix(ob.patp(_point))}-${networkRevision}.key`;
129 }, [_point, networkRevision]);
131 const download = useCallback(() => {
132 if (typeof keyfile !== 'string') {
133 return;
134 }
136 saveAs(
137 new Blob([keyfile], {
138 type: 'text/plain;charset=utf-8',
139 }),
140 filename
141 );
142 setDownloaded(true);
143 }, [filename, keyfile]);
145 useEffect(() => {
146 generate();
147 }, [generate]);
149 const values = {
150 generating,
151 available,
152 downloaded,
153 download,
154 filename,
155 notice,
156 keyfile,
157 code,
158 };
160 return { ...values, bind: values };