on master help sign in
Merge pull request #360 from urbit/m/mnemonic-fixes
d0a1881Fang
src/form/validators.js+4−1
@@ -4,6 +4,7 @@ import {
4 validateNotEmpty,
4 validateNotEmpty,
5 validatePatq,
5 validatePatq,
6 validateMnemonic,
6 validateMnemonic,
7+ validateHdPath,
7 validatePoint,
8 validatePoint,
8 validateMaximumPatpByteLength,
9 validateMaximumPatpByteLength,
9 validateOneOf,
10 validateOneOf,
@@ -60,6 +61,8 @@ export const hasErrors = iter =>
60
61
61export const buildPatqValidator = (validators = []) =>
62export const buildPatqValidator = (validators = []) =>
62 buildValidator([validateNotEmpty, validatePatq, ...validators]);
63 buildValidator([validateNotEmpty, validatePatq, ...validators]);
64+export const buildAnyMnemonicValidator = () =>
65+ buildValidator([validateNotEmpty]);
63export const buildMnemonicValidator = () =>
66export const buildMnemonicValidator = () =>
64 buildValidator([validateNotEmpty, validateMnemonic]);
67 buildValidator([validateNotEmpty, validateMnemonic]);
65export const buildCheckboxValidator = mustBe =>
68export const buildCheckboxValidator = mustBe =>
@@ -68,7 +71,7 @@ export const buildCheckboxValidator = mustBe =>
68 ]);
71 ]);
69export const buildPassphraseValidator = () => buildValidator([]);
72export const buildPassphraseValidator = () => buildValidator([]);
70// TODO: validate hdpath format
73// TODO: validate hdpath format
71−export const buildHdPathValidator = () => buildValidator([validateNotEmpty]);
74+export const buildHdPathValidator = () => buildValidator([validateHdPath]);
72export const buildPointValidator = (size = 4, validators = []) =>
75export const buildPointValidator = (size = 4, validators = []) =>
73 buildValidator([
76 buildValidator([
74 validateNotEmpty,
77 validateNotEmpty,
src/lib/validators.js+4
@@ -24,6 +24,10 @@ const isHexPrefixed = /^0x/;
24export const validateMnemonic = v =>
24export const validateMnemonic = v =>
25 !bip39.validateMnemonic(v) && 'This is not a valid mnemonic.';
25 !bip39.validateMnemonic(v) && 'This is not a valid mnemonic.';
26
26
27+const isHdPath = /^m(\/[0-9]+'?)*$/;
28+export const validateHdPath = v =>
29+ !isHdPath.test(v) && 'Invalid HD derivation path.';
30+
27// Checks an empty field
31// Checks an empty field
28export const validateNotEmpty = v =>
32export const validateNotEmpty = v =>
29 (v === undefined || v.length === 0) && 'This field is required.';
33 (v === undefined || v.length === 0) && 'This field is required.';
src/lib/wallet.js+10−4
@@ -81,10 +81,16 @@ export const urbitWalletFromTicket = async (ticket, point, passphrase) => {
81 });
81 });
82};
82};
83
83
84−export const walletFromMnemonic = (mnemonic, hdpath, passphrase) => {
84+export const walletFromMnemonic = (
85+ mnemonic,
86+ hdpath,
87+ passphrase,
88+ skipMnemonicCheck
89+) => {
90+ const seed =
85− const seed = bip39.validateMnemonic(mnemonic)
91+ skipMnemonicCheck || bip39.validateMnemonic(mnemonic)
86− ? Just(bip39.mnemonicToSeed(mnemonic, passphrase))
92+ ? Just(bip39.mnemonicToSeed(mnemonic, passphrase))
87− : Nothing();
93+ : Nothing();
88
94
89 const toWallet = (sd, path) => {
95 const toWallet = (sd, path) => {
90 let wal;
96 let wal;
src/views/Login/Mnemonic.js+36−23
@@ -1,15 +1,16 @@
1−import React, { useCallback, useMemo } from 'react';
1+import React, { useCallback, useState, useMemo } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3import { Just, Nothing } from 'folktale/maybe';
3import { Just, Nothing } from 'folktale/maybe';
4import { Grid, CheckboxInput } from 'indigo-react';
4import { Grid, CheckboxInput } from 'indigo-react';
5
5
6import { useWallet } from 'store/wallet';
6import { useWallet } from 'store/wallet';
7
7
8−import { walletFromMnemonic, WALLET_TYPES } from 'lib/wallet';
8+import { walletFromMnemonic, WALLET_TYPES, DEFAULT_HD_PATH } from 'lib/wallet';
9import useLoginView from 'lib/useLoginView';
9import useLoginView from 'lib/useLoginView';
10import { MnemonicInput, HdPathInput, PassphraseInput } from 'form/Inputs';
10import { MnemonicInput, HdPathInput, PassphraseInput } from 'form/Inputs';
11import {
11import {
12 composeValidator,
12 composeValidator,
13+ buildAnyMnemonicValidator,
13 buildMnemonicValidator,
14 buildMnemonicValidator,
14 buildCheckboxValidator,
15 buildCheckboxValidator,
15 buildPassphraseValidator,
16 buildPassphraseValidator,
@@ -23,32 +24,36 @@ import SubmitButton from 'form/SubmitButton';
23export default function Mnemonic({ className, goHome }) {
24export default function Mnemonic({ className, goHome }) {
24 useLoginView(WALLET_TYPES.MNEMONIC);
25 useLoginView(WALLET_TYPES.MNEMONIC);
25
26
26− const {
27− setWallet,
28− setAuthMnemonic,
27+ const { setWallet, setAuthMnemonic, setWalletHdPath } = useWallet();
29− walletHdPath,
30− setWalletHdPath,
31− } = useWallet();
32
28
29+ const [anyMnemonic, setAnyMnemonic] = useState(false);
30+
33− const validate = useMemo(
31+ const validate = useMemo(() => {
34− () =>
32+ const mnemonicValidator = anyMnemonic
33+ ? buildAnyMnemonicValidator()
34+ : buildMnemonicValidator();
35− composeValidator({
35+ return composeValidator({
36− useAdvanced: buildCheckboxValidator(),
36+ useAdvanced: buildCheckboxValidator(),
37− mnemonic: buildMnemonicValidator(),
37+ mnemonic: mnemonicValidator,
38− passphrase: buildPassphraseValidator(),
38+ passphrase: buildPassphraseValidator(),
39− hdpath: buildHdPathValidator(),
39+ hdpath: buildHdPathValidator(),
40− }),
40+ });
41− []
41+ }, [anyMnemonic]);
42− );
43
42
44 // when the properties change, re-derive wallet and set global state
43 // when the properties change, re-derive wallet and set global state
45 const onValues = useCallback(
44 const onValues = useCallback(
46 ({ valid, values }) => {
45 ({ valid, values }) => {
46+ setAnyMnemonic(values.anyMnemonic);
47 if (valid) {
47 if (valid) {
48 setWalletHdPath(values.hdpath);
48 setWalletHdPath(values.hdpath);
49 setAuthMnemonic(Just(values.mnemonic));
49 setAuthMnemonic(Just(values.mnemonic));
50 setWallet(
50 setWallet(
51− walletFromMnemonic(values.mnemonic, values.hdpath, values.passphrase)
51+ walletFromMnemonic(
52+ values.mnemonic,
53+ values.hdpath,
54+ values.passphrase,
55+ values.anyMnemonic
56+ )
52 );
57 );
53 } else {
58 } else {
54 setAuthMnemonic(Nothing());
59 setAuthMnemonic(Nothing());
@@ -58,10 +63,11 @@ export default function Mnemonic({ className, goHome }) {
58 [setAuthMnemonic, setWallet, setWalletHdPath]
63 [setAuthMnemonic, setWallet, setWalletHdPath]
59 );
64 );
60
65
61− const initialValues = useMemo(
66+ const initialValues = {
67+ hdpath: DEFAULT_HD_PATH,
62− () => ({ hdpath: walletHdPath, useAdvanced: false }),
68+ useAdvanced: false,
63− [walletHdPath]
69+ anyMnemonic: false,
64− );
70+ };
65
71
66 return (
72 return (
67 <Grid className={cn('mt4', className)}>
73 <Grid className={cn('mt4', className)}>
@@ -79,6 +85,13 @@ export default function Mnemonic({ className, goHome }) {
79 label="BIP39 Mnemonic"
85 label="BIP39 Mnemonic"
80 />
86 />
81
87
88+ <Grid.Item
89+ full
90+ as={CheckboxInput}
91+ name="anyMnemonic"
92+ label="Skip mnemonic validation"
93+ />
94+
82 <Condition when="useAdvanced" is={true}>
95 <Condition when="useAdvanced" is={true}>
83 <Grid.Item
96 <Grid.Item
84 full
97 full
src/views/Senate.js+11−33
@@ -1,42 +1,26 @@
1import React, { useCallback, useMemo, useState } from 'react';
1import React, { useCallback, useMemo, useState } from 'react';
2−import cn from 'classnames';
3−import { Grid, Text, Input, P, LinkButton } from 'indigo-react';
2+import { Grid, Text, P, LinkButton } from 'indigo-react';
4import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
5−import ob from 'urbit-ob';
6
4
7import { useNetwork } from 'store/network';
5import { useNetwork } from 'store/network';
8−import { usePointCache } from 'store/pointCache';
9import { usePointCursor } from 'store/pointCursor';
6import { usePointCursor } from 'store/pointCursor';
10
7
11import * as need from 'lib/need';
8import * as need from 'lib/need';
12import useEthereumTransaction from 'lib/useEthereumTransaction';
9import useEthereumTransaction from 'lib/useEthereumTransaction';
13import { GAS_LIMITS } from 'lib/constants';
10import { GAS_LIMITS } from 'lib/constants';
14−import patp2dec from 'lib/patp2dec';
15−import { getSpawnCandidate } from 'lib/child';
16import { useLocalRouter } from 'lib/LocalRouter';
11import { useLocalRouter } from 'lib/LocalRouter';
17−import useConstant from 'lib/useConstant';
18
12
19import { keccak256 } from 'lib/wallet';
13import { keccak256 } from 'lib/wallet';
20
14
21import ViewHeader from 'components/ViewHeader';
15import ViewHeader from 'components/ViewHeader';
22import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
16import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
23import View from 'components/View';
17import View from 'components/View';
24−import { PointInput, AddressInput } from 'form/Inputs';
25−import {
26− composeValidator,
27− buildPointValidator,
28− buildAddressValidator,
29− hasErrors,
30−} from 'form/validators';
31import BridgeForm from 'form/BridgeForm';
18import BridgeForm from 'form/BridgeForm';
32−import FormError from 'form/FormError';
33−import CopiableAddress from 'components/CopiableAddress';
34import convertToInt from 'lib/convertToInt';
19import convertToInt from 'lib/convertToInt';
35
20
36function useCastDocumentVote() {
21function useCastDocumentVote() {
37 const { contracts } = useNetwork();
22 const { contracts } = useNetwork();
38 const { pointCursor } = usePointCursor();
23 const { pointCursor } = usePointCursor();
39− const { syncDetails } = usePointCache();
40
24
41 const _contracts = need.contracts(contracts);
25 const _contracts = need.contracts(contracts);
42 const _point = need.point(pointCursor);
26 const _point = need.point(pointCursor);
@@ -66,15 +50,9 @@ export default function Senate() {
66 const _contracts = need.contracts(contracts);
50 const _contracts = need.contracts(contracts);
67 const _point = convertToInt(need.point(pointCursor), 10);
51 const _point = convertToInt(need.point(pointCursor), 10);
68
52
69− const {
70− construct,
71− unconstruct,
72− inputsLocked,
73− completed,
74− bind,
75− } = useCastDocumentVote();
53+ const { construct, bind } = useCastDocumentVote();
76
54
77− const [documentHash, setDocumentHash] = useState('0x...');
55+ // const [documentHash, setDocumentHash] = useState('0x...');
78 const [majorities, setMajorities] = useState([]);
56 const [majorities, setMajorities] = useState([]);
79 const [proposals, setProposals] = useState([]);
57 const [proposals, setProposals] = useState([]);
80 const [polls, setPolls] = useState({});
58 const [polls, setPolls] = useState({});
@@ -103,7 +81,7 @@ export default function Senate() {
103 setPolls(polls);
81 setPolls(polls);
104 setLoading(false);
82 setLoading(false);
105 return;
83 return;
106− }, [_contracts]);
84+ }, [_contracts, _point]);
107
85
108 const [open, closed] = useMemo(() => {
86 const [open, closed] = useMemo(() => {
109 let open = [];
87 let open = [];
@@ -185,15 +163,15 @@ export default function Senate() {
185 </>
163 </>
186 );
164 );
187 });
165 });
188− }, [open, polls, votingOn]);
166+ }, [open, polls, votingOn, doVote]);
189
167
190 const onDocumentChange = useCallback(({ valid, values }) => {
168 const onDocumentChange = useCallback(({ valid, values }) => {
191− if (values.document) {
169+ // if (values.document) {
192− const hash = '0x' + keccak256(values.document.trim()).toString('hex');
170+ // const hash = '0x' + keccak256(values.document.trim()).toString('hex');
193− setDocumentHash(hash);
171+ // setDocumentHash(hash);
194− } else {
172+ // } else {
195− setDocumentHash('0x...');
173+ // setDocumentHash('0x...');
196− }
174+ // }
197 }, []);
175 }, []);
198
176
199 return (
177 return (