on 1226972 help sign in
bridge/src/lib/useKeyfileGenerator.ts
140 lines 3.5 kB history raw
1import { useCallback, useMemo, useEffect, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import saveAs from 'file-saver';
5import { useWallet } from 'store/wallet';
6import { useRollerStore } from 'store/rollerStore';
8import { generateCode } from 'lib/networkCode';
10import {
11 attemptNetworkSeedDerivation,
12 keysMatchChain,
13 deriveNetworkKeys,
14 compileMultiKey,
15} from './keys';
16import { stripSigPrefix } from 'form/formatters';
18interface useKeyfileGeneratorArgs {
19 seed?: string;
22/**
23 * seed - (optional) derived from wallet, mnemonic, or token by default (if possible)
24 */
25export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
26 const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
27 const { point } = useRollerStore();
29 const [notice, setNotice] = useState('Deriving networking keys...');
30 const [downloaded, setDownloaded] = useState(false);
31 const [generating, setGenerating] = useState(true);
32 const [keyfile, setKeyfile] = useState<boolean | string>(false);
33 const [code, setCode] = useState(false);
35 const networkRevision = Number(point.keyRevisionNumber);
36 const canManage = point.isOwner || point.isManagementProxy;
38 const hasNetworkKeys = networkRevision > 0;
39 const available = canManage && hasNetworkKeys && !!keyfile;
41 const generate = useCallback(async () => {
42 if (!hasNetworkKeys) {
43 setGenerating(false);
44 setNotice('Network keys not yet set.');
45 console.log(
46 `no networking keys available for revision ${networkRevision}`
47 );
48 return;
49 }
51 const networkSeed = seed
52 ? Just(seed)
53 : await attemptNetworkSeedDerivation({
54 urbitWallet,
55 wallet,
56 authMnemonic,
57 details: point,
58 authToken,
59 point: point.value,
60 revision: networkRevision,
61 });
63 if (Nothing.hasInstance(networkSeed)) {
64 setGenerating(false);
65 setNotice(
66 'Custom or nondeterministic networking keys cannot be re-downloaded.'
67 );
68 console.log(`seed is nondeterminable for revision ${networkRevision}`);
69 return;
70 }
72 const _networkSeed = networkSeed.value;
74 const pair = deriveNetworkKeys(_networkSeed);
76 if (!keysMatchChain(pair, point)) {
77 setGenerating(false);
78 setNotice('Derived networking keys do not match on-chain details.');
79 console.log(`keys do not match details for revision ${networkRevision}`);
80 return;
81 }
83 setNotice('');
84 setCode(generateCode(pair));
85 setKeyfile(
86 compileMultiKey(point.value, [
87 {
88 revision: networkRevision,
89 pair: pair,
90 },
91 ])
92 );
93 setGenerating(false);
94 }, [
95 networkRevision,
96 hasNetworkKeys,
97 seed,
98 urbitWallet,
99 wallet,
100 authMnemonic,
101 setCode,
102 point,
103 authToken,
104 ]);
106 const filename = useMemo(() => {
107 return `${stripSigPrefix(point.patp)}-${networkRevision}.key`;
108 }, [point, networkRevision]);
110 const download = useCallback(() => {
111 if (typeof keyfile !== 'string') {
112 return;
113 }
115 saveAs(
116 new Blob([keyfile], {
117 type: 'text/plain;charset=utf-8',
118 }),
119 filename
120 );
121 setDownloaded(true);
122 }, [filename, keyfile]);
124 useEffect(() => {
125 generate();
126 }, [generate]);
128 const values = {
129 generating,
130 available,
131 downloaded,
132 download,
133 filename,
134 notice,
135 keyfile,
136 code,
137 };
139 return { ...values, bind: values };