1import * as need from 'lib/need';
2import saveAs from 'file-saver';
3import ob from 'urbit-ob';
4import { Just, Nothing } from 'folktale/maybe';
6import { useCallback, useEffect, useMemo, useState } from 'react';
7import { usePointCache } from 'store/pointCache';
8import { usePointCursor } from 'store/pointCursor';
9import { useWallet } from 'store/wallet';
10import { deriveNetworkKeys } from 'urbit-key-generation';
11import { convertToInt } from './convertToInt';
13 attemptNetworkSeedDerivation,
17import { generateCode } from './networkCode';
18import { L1Point } from './types/L1Point';
19import useCurrentPermissions from './useCurrentPermissions';
20import { stripSigPrefix } from 'form/formatters';
22interface useMultikeyFileGeneratorArgs {
30 * - seed: derived from wallet, mnemonic, or token (if posisble)
31 * - point: the current pointCursor
33export default function useMultikeyFileGenerator({
37}: useMultikeyFileGeneratorArgs) {
38 const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
39 const { pointCursor }: any = usePointCursor();
40 const { syncDetails, getDetails }: any = usePointCache();
41 const { isOwner, isManagementProxy } = useCurrentPermissions();
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 = useMemo(() => point || need.point(pointCursor), [
53 const details = getDetails(_point);
54 const _details: L1Point | null = useMemo(
57 Just: d => need.details(d),
63 const currentRevision: number = useMemo(
66 Just: ({ value }) => convertToInt(value.keyRevisionNumber, 10),
71 const nextRevision = useMemo(() => currentRevision + 1, [currentRevision]);
73 const pairFromRevision = useCallback(
74 async (revision: number) => {
79 const networkSeed = seed
81 : await attemptNetworkSeedDerivation({
82 urbitWallet: seedWallet || urbitWallet,
91 if (Nothing.hasInstance(networkSeed)) {
94 'Custom or nondeterministic networking keys cannot be re-downloaded.'
96 console.log(`seed is nondeterminable for revision ${revision}`);
100 const _networkSeed = networkSeed.value;
102 return deriveNetworkKeys(_networkSeed);
116 const hasNetworkKeys = currentRevision > 0;
118 (isOwner || isManagementProxy) && hasNetworkKeys && !!keyfile;
120 const generate = useCallback(async () => {
121 if (!hasNetworkKeys) {
122 setGenerating(false);
123 setNotice('Network keys not yet set.');
125 `no networking keys available for revision ${currentRevision}`
130 // TODO: Do we still need this? The legacy implementation in useKeyfileGenerator
131 // performed this guard statement
133 // const currentPair = await pairFromRevision(currentRevision);
135 // if (!currentPair || !keysMatchChain(currentPair, _details)) {
136 // setGenerating(false);
137 // setNotice('Derived networking keys do not match on-chain details.');
138 // console.log(`keys do not match details for revision ${currentRevision}`);
142 // const nextPair = await pairFromRevision(nextRevision);
144 const [currentPair, nextPair] = await Promise.all([
145 pairFromRevision(currentRevision),
146 pairFromRevision(nextRevision),
150 setCode(generateCode(currentPair));
160 setGenerating(false);
161 }, [_point, currentRevision, hasNetworkKeys, nextRevision, pairFromRevision]);
163 const filename = useMemo(() => {
164 return `${stripSigPrefix(ob.patp(_point))}-${currentRevision}.key`;
165 }, [_point, currentRevision]);
167 const download = useCallback(() => {
168 if (typeof keyfile !== 'string') {
173 new Blob([keyfile], {
174 type: 'text/plain;charset=utf-8',
179 }, [filename, keyfile]);
183 }, [_point, syncDetails]);
200 return { ...output, bind: output };
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list