on master help sign in
Merge pull request #249 from urbit/feat/private-key-input

feat: hex inputs enforce 0x prefix and private key inputs strip it

commit3d8d2c7742c0f29a99723bbc2a9e26db0a0a89c9 authorMatt Condon <mattgcondon@gmail.com> dateMon 26 Aug 2019, 18:59 (7 years ago) parent604b738115c41e
5 files changed+62−16
src/form/Inputs.js+18−2 src/form/formatters.js+18−7 src/form/validators.js+14−1 src/lib/validators.js+8−2 src/views/Login/PrivateKey.js+4−4
src/form/Inputs.js+18−2
@@ -7,6 +7,8 @@ import {
77 buildFormatter,
88 downcase,
99 ensurePatFormat,
10+ stripHexPrefix,
11+ ensureHexPrefix,
1012} from 'form/formatters';
1113import { DEFAULT_HD_PATH } from 'lib/wallet';
1214import InputSigil from 'components/InputSigil';
@@ -17,7 +19,9 @@ const PLACEHOLDER_MNEMONIC =
1719 'example crew supreme gesture quantum web media hazard theory mercy wing kitten';
1820const PLACEHOLDER_TICKET = '~sampel-ticlyt-migfun-falmel';
1921const PLACEHOLDER_ADDRESS = '0x';
20−const PLACEHOLDER_PRIVATE_KEY = '0x';
22+const PLACEHOLDER_HEX = '0x';
23+const PLACEHOLDER_PRIVATE_KEY =
24+ 'a44de2416ee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
2125const PLACEHOLDER_EMAIL = 'email@example.com';
2226
2327const formatPat = buildFormatter([downcase, ensurePatFormat]);
@@ -136,11 +140,23 @@ export function HexInput({ ...rest }) {
136140 return (
137141 <Input
138142 type="text"
139− placeholder={PLACEHOLDER_PRIVATE_KEY}
143+ placeholder={PLACEHOLDER_HEX}
140144 autoCapitalize="none"
141145 autoComplete="off"
142146 autoCorrect="off"
143147 mono
148+ config={{ parse: ensureHexPrefix }}
149+ {...rest}
150+ />
151+ );
152+}
153+
154+export function PrivateKeyInput({ ...rest }) {
155+ return (
156+ <HexInput
157+ type="password"
158+ placeholder={PLACEHOLDER_PRIVATE_KEY}
159+ config={{ parse: stripHexPrefix }}
144160 {...rest}
145161 />
146162 );
src/form/formatters.js+18−7
@@ -1,5 +1,6 @@
11import { compose, strSplice } from 'lib/lib';
22
3+const HEX_PREFIX = '0x';
34const TICKET_MAX_BYTE_LEN = 32; // tickets can be as large as 32 bytes
45const PAT_BLOCK_CHAR_LENGTH = 6; // pat{p,q} blocks are 6 characters long
56
@@ -38,6 +39,14 @@ export const ensurePatFormat = s => {
3839 return s;
3940};
4041
42+export const ensureHexPrefix = s => {
43+ if (!s || s.length < HEX_PREFIX.length) {
44+ return s || '';
45+ }
46+
47+ return s.indexOf(HEX_PREFIX) !== 0 ? `${HEX_PREFIX}${s}` : s;
48+};
49+
4150export const convertToNumber = s => {
4251 try {
4352 return parseInt(s, 10);
@@ -54,10 +63,12 @@ export const downcase = s => {
5463 return s.toLowerCase();
5564};
5665
57−// const hideAllButLast = s => {
58−// const ll = s[s.length -1];
59−// const bs = fill(s.length - 1, '•')
60−// return `${bs}${ll}`
61−// };
62−//
63−// const hideAll = s => fill(s.length, '•');
66+export const stripHexPrefix = s => {
67+ if (!s) {
68+ return s;
69+ }
70+
71+ return s.toLowerCase().indexOf(HEX_PREFIX) === 0
72+ ? s.slice(HEX_PREFIX.length)
73+ : s;
74+};
src/form/validators.js+14−1
@@ -13,9 +13,14 @@ import {
1313 validateGreaterThan,
1414 validateEmail,
1515 validateNotNullAddress,
16+ validateHexPrefix,
17+ validateLength,
1618} from 'lib/validators';
1719import isPromise from 'lib/isPromise';
1820
21+const PRIVATE_KEY_CHAR_LENGTH = 64; // 64 hex characters
22+const ADDRESS_CHAR_LENGTH = 40; // 40 hex characters
23+
1924// iterate over validators, exiting early if there's an error
2025const buildValidator = (validators = [], validate) => value => {
2126 for (const validator of validators) {
@@ -75,15 +80,23 @@ export const buildSelectValidator = options =>
7580export const buildHexValidator = length =>
7681 buildValidator([
7782 validateNotEmpty,
83+ validateHexPrefix,
7884 validateHexString,
7985 validateHexLength(length),
8086 ]);
87+export const buildPrivateKeyValidator = () =>
88+ buildValidator([
89+ validateNotEmpty,
90+ validateHexString,
91+ validateLength(PRIVATE_KEY_CHAR_LENGTH),
92+ ]);
8193export const buildUploadValidator = () => buildValidator([validateNotEmpty]);
8294export const buildAddressValidator = () =>
8395 buildValidator([
8496 validateNotEmpty,
97+ validateHexPrefix,
8598 validateHexString,
86− validateHexLength(40),
99+ validateHexLength(ADDRESS_CHAR_LENGTH),
87100 validateNotNullAddress,
88101 validateEthereumAddress,
89102 ]);
src/lib/validators.js+8−2
@@ -14,8 +14,11 @@ import { MIN_GALAXY, MAX_GALAXY } from './constants';
1414// via: https://emailregex.com/
1515const emailRegExp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1616
17−// is this only hex values with a 0x prefix?
18−const isHexString = /0x[0-9A-Fa-f]/;
17+// validate only strings that use hex characters
18+const isHexString = /[0-9A-Fa-f]/;
19+
20+// validate only strings that are prefixed with 0x
21+const isHexPrefixed = /^0x/;
1922
2023// Validates a bip39 mnemonic
2124export const validateMnemonic = v =>
@@ -64,6 +67,9 @@ export const validateOneOf = (options = []) => v =>
6467export const validateHexString = v =>
6568 !isHexString.test(v) && 'This is not a valid hex string.';
6669
70+export const validateHexPrefix = v =>
71+ !isHexPrefixed.test(v) && 'Must include 0x prefix.';
72+
6773export const validateEthereumAddress = v =>
6874 !isValidAddress(v) && 'This is not a valid Ethereum address.';
6975
src/views/Login/PrivateKey.js+4−4
@@ -9,8 +9,8 @@ import useLoginView from 'lib/useLoginView';
99
1010import FormError from 'form/FormError';
1111import BridgeForm from 'form/BridgeForm';
12−import { HexInput } from 'form/Inputs';
13−import { buildHexValidator, composeValidator } from 'form/validators';
12+import { PrivateKeyInput } from 'form/Inputs';
13+import { composeValidator, buildPrivateKeyValidator } from 'form/validators';
1414
1515import SubmitButton from 'form/SubmitButton';
1616
@@ -22,7 +22,7 @@ export default function PrivateKey({ className, goHome }) {
2222 const validate = useMemo(
2323 () =>
2424 composeValidator({
25− privateKey: buildHexValidator(64),
25+ privateKey: buildPrivateKeyValidator(64),
2626 }),
2727 []
2828 );
@@ -47,7 +47,7 @@ export default function PrivateKey({ className, goHome }) {
4747 <>
4848 <Grid.Item
4949 full
50− as={HexInput}
50+ as={PrivateKeyInput}
5151 name="privateKey"
5252 label="Private key"
5353 />