@@ -1,6 +1,6 @@
11import * as bip39 from 'bip39';
22import * as ob from 'urbit-ob';
3−import { identity, includes } from 'lodash';
3+import { includes } from 'lodash';
44
55import { isValidAddress, ETH_ZERO_ADDR, ETH_ZERO_ADDR_SHORT } from './wallet';
66import patp2dec from './patp2dec';
@@ -14,274 +14,83 @@ 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 64 hex chars?
18−const plain64CharHexValue = /[0-9A-Fa-f]{64}/;
19−
2017// is this only hex values with a 0x prefix?
2118const isHexString = /0x[0-9A-Fa-f]/;
2219
23−// Wraps single validation functions in a controlled and predictable way.
24−export const simpleValidatorWrapper = ({
25− prevMessage,
26− transform = identity,
27− validator,
28− error,
29−}) => {
30− // If a previous validation has already failed, skip this validation and
31− // return the prev message to the next stage in the validation function chain.
32− // Failed validations should drop all the way down the chain and drop out of
33− // the output.
34− if (!prevMessage.pass) {
35− return prevMessage;
36− }
37−
38− // Run the validator and return the result.
39− const pass = validator(prevMessage.data);
40− const data = pass ? transform(prevMessage.data) : prevMessage.data;
41−
42− return newMessage(data, pass, !pass && error);
43−};
44−
45−// Validation message
46−// {
47−// data: ...
48−// pass: ...
49−// error: ...
50−// }
51−// Creates a new validation message in a uniform way.
52−const newMessage = (data, pass, error) => ({
53− // The input data
54− data,
55− // Has the data passed validation?
56− pass,
57− // If data has failed a validator, the error message goes here.
58− error,
59−});
60−
61−// A validator that always passes.
62−export const kDefaultValidator = data => newMessage(data, true, null);
63−
6420// Validates a bip39 mnemonic
65−export const validateMnemonic = m =>
66− simpleValidatorWrapper({
67− prevMessage: m,
68− validator: d => bip39.validateMnemonic(d),
69− error: 'This is not a valid mnemonic.',
70− });
21+export const validateMnemonic = v =>
22+ !bip39.validateMnemonic(v) && 'This is not a valid mnemonic.';
7123
7224// Checks an empty field
73−export const validateNotEmpty = m =>
74− simpleValidatorWrapper({
75− prevMessage: m,
76− validator: d => {
77− try {
78− return d.length > 0;
79− } catch {
80− return false;
81− }
82− },
83− error: 'This field is required.',
84− });
25+export const validateNotEmpty = v =>
26+ v.length === 0 && 'This field is required.';
8527
8628// Checks if a patp is a valid galaxy
87−export const validateGalaxy = m =>
88− simpleValidatorWrapper({
89− prevMessage: m,
90− validator: d => {
91− let point;
92− try {
93− point = patp2dec(d);
94− return point >= MIN_GALAXY && point <= MAX_GALAXY;
95− } catch (e) {
96− return false;
97− }
98− },
99− error: 'This is not a valid galaxy.',
100− });
101−
102−export const validatePoint = m =>
103− simpleValidatorWrapper({
104− prevMessage: m,
105− validator: d => {
106− try {
107− return ob.isValidPatp(d);
108− } catch (e) {
109− return false;
110− }
111− },
112− error: 'This is not a valid point.',
113− });
114−
115−export const validateTicket = m =>
116− simpleValidatorWrapper({
117− prevMessage: m,
118− validator: d => {
119− try {
120− return ob.isValidPatq(d);
121− } catch (e) {
122− return false;
123− }
124− },
125− error: 'This is not a valid ticket.',
126− });
127−
128−export const validateShard = m =>
129− simpleValidatorWrapper({
130− prevMessage: m,
131− validator: d => {
132− try {
133− return ob.isValidPatq(d);
134− } catch (e) {
135− return false;
136− }
137− },
138− error: 'This is not a valid shard.',
139− });
140−
141−export const validateOneOf = (options = []) => m =>
142− simpleValidatorWrapper({
143− prevMessage: m,
144− validator: d => includes(options, d),
145− error: `Is not a valid option.`,
146− });
147−
148−export const validateHexString = m =>
149− simpleValidatorWrapper({
150− prevMessage: m,
151− validator: d => isHexString.test(d),
152− error: 'This is not a valid hex string.',
153− });
154−
155−// @deprecate
156−export const validateNetworkKey = m =>
157− simpleValidatorWrapper({
158− prevMessage: m,
159− validator: d => plain64CharHexValue.test(d),
160− error: 'This is not a valid network key.',
161− });
29+export const validateGalaxy = v => {
30+ try {
31+ const point = patp2dec(v);
32+ const isValidGalaxy = point >= MIN_GALAXY && point <= MAX_GALAXY;
33+ if (!isValidGalaxy) {
34+ throw new Error();
35+ }
36+ } catch {
37+ return 'This is not a valid galaxy.';
38+ }
39+};
16240
163−// @deprecate
164−export const validateNetworkSeed = m =>
165− simpleValidatorWrapper({
166− prevMessage: m,
167− validator: d => plain64CharHexValue.test(d),
168− error: 'This is not a valid network seed.',
169− });
41+export const validatePoint = v => {
42+ try {
43+ if (!ob.isValidPatp(v)) {
44+ throw new Error();
45+ }
46+ } catch {
47+ return 'This is not a valid point.';
48+ }
49+};
17050
171−// Checks if a string is a valid ethereum address
172−export const validateEthereumAddress = m =>
173− simpleValidatorWrapper({
174− prevMessage: m,
175− validator: d => isValidAddress(d),
176− error: 'This is not a valid Ethereum address.',
177− });
51+export const validatePatq = v => {
52+ try {
53+ if (!ob.isValidPatq(v)) {
54+ throw new Error();
55+ }
56+ } catch {
57+ return 'This is not a valid ticket.';
58+ }
59+};
17860
179−export const validateEmail = m =>
180− simpleValidatorWrapper({
181− prevMessage: m,
182− validator: d => emailRegExp.test(d),
183− error: 'This is not a valid email address.',
184− });
61+export const validateOneOf = (options = []) => v =>
62+ !includes(options, v) && 'Is not a valid option.';
18563
186−export const validateInt = m =>
187− simpleValidatorWrapper({
188− prevMessage: m,
189− transform: d => parseInt(d, 10),
190− validator: d => {
191− try {
192− parseInt(d, 10);
193− return;
194− } catch {
195− return false;
196− }
197− },
198− error: 'This is not a valid number.',
199− });
64+export const validateHexString = v =>
65+ !isHexString.test(v) && 'This is not a valid hex string.';
20066
201−export const validateExactly = (value, error) => m =>
202− simpleValidatorWrapper({
203− prevMessage: m,
204− validator: d => d === value,
205− error,
206− });
67+export const validateEthereumAddress = v =>
68+ !isValidAddress(v) && 'This is not a valid Ethereum address.';
20769
208−export const validateNotAny = (values = []) => m =>
209− simpleValidatorWrapper({
210− prevMessage: m,
211− validator: d => !values.includes(d),
212− error: `Cannot be ${m.data}.`,
213− });
70+export const validateEmail = v =>
71+ !emailRegExp.test(v) && 'This is not a valid email address.';
21472
215−export const validateLength = l => m =>
216− simpleValidatorWrapper({
217− prevMessage: m,
218− validator: d => {
219− try {
220− return d.length === l;
221− } catch {
222− return false;
223− }
224− },
225− error: `Must be exactly ${l} characters.`,
226− });
73+export const validateExactly = (value, error) => v => v !== value && error;
22774
228−export const validateHexLength = l => m =>
229− simpleValidatorWrapper({
230− prevMessage: m,
231− validator: d => {
232− try {
233− return d.length === l + 2;
234− } catch {
235− return false;
236− }
237− },
238− error: `Must be exactly ${l} hex characters.`,
239− });
75+export const validateNotAny = (values = []) => v =>
76+ values.includes(v) && `Cannot be ${v}.`;
24077
241−export const validateMaximumLength = l => m =>
242− simpleValidatorWrapper({
243− prevMessage: m,
244− validator: d => {
245− try {
246− return d.length <= l;
247− } catch {
248− return false;
249− }
250− },
251− error: `Must be ${l} characters or fewer.`,
252− });
78+export const validateLength = l => v =>
79+ v.length !== l && `Must be exactly ${l} characters.`;
25380
254−export const validateGreaterThan = l => m =>
255− simpleValidatorWrapper({
256− prevMessage: m,
257− validator: d => d > l,
258− error: `Must be at least ${l}.`,
259− });
81+export const validateHexLength = l => v =>
82+ v.length !== l + 2 && `Must be exactly ${l} hex characters.`;
26083
261−export const validateInSet = (set, error) => m =>
262− simpleValidatorWrapper({
263− prevMessage: m,
264− validator: d => set.has(d),
265− error,
266− });
84+export const validateMaximumLength = l => v =>
85+ v.length > l && `Must be ${l} characters or fewer.`;
26786
268−export const validateNameInNumberSet = (set, error) => m =>
269− simpleValidatorWrapper({
270− prevMessage: m,
271− validator: p => {
272− const num = patp2dec(p);
273− return set.has(num);
274− },
275− error,
276− });
87+export const validateGreaterThan = l => v =>
88+ !(v > l) && `Must be at least ${l}.`;
27789
278−export const validatePatpByteLength = byteLength => {
279− return validateLength(patpStringLength(byteLength));
280−};
90+export const validateInSet = (set, error) => v => !set.has(v) && error;
28191
282−export const validateMaximumPatpByteLength = byteLength => {
283− return validateMaximumLength(patpStringLength(byteLength));
284−};
92+export const validateMaximumPatpByteLength = byteLength =>
93+ validateMaximumLength(patpStringLength(byteLength));
28594
28695export const validateNotNullAddress = validateNotAny([
28796 ETH_ZERO_ADDR,