on cd91628 help sign in
bridge/src/lib/validators.js
210 lines 5.1 kB history raw
1import * as bip39 from 'bip39';
2import * as ob from 'urbit-ob';
3import { identity } from 'lodash';
5import { isValidAddress } from './wallet';
6import patp2dec from './patp2dec';
8// NOTE: do not use the /g modifier for these regexes
9// https://stackoverflow.com/a/21373261
10// https://stackoverflow.com/a/1520853
12// via: https://emailregex.com/
13const 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,}))$/;
15// is this 64 hex chars?
16const plain64CharHexValue = /[0-9A-Fa-f]{64}/;
18// is this only hex values with a 0x prefix?
19const isHexString = /0x[0-9A-Fa-f]/;
21// Wraps single validation functions in a controlled and predictable way.
22export const simpleValidatorWrapper = ({
23 prevMessage,
24 transform = identity,
25 validator,
26 error,
27}) => {
28 // If a previous validation has already failed, skip this validation and
29 // return the prev message to the next stage in the validation function chain.
30 // Failed validations should drop all the way down the chain and drop out of
31 // the output.
32 if (!prevMessage.pass) {
33 return prevMessage;
34 }
36 // Run the validator and return the result.
37 const pass = validator(prevMessage.data);
38 const data = pass ? transform(prevMessage.data) : prevMessage.data;
40 return newMessage(data, pass, !pass && error);
41};
43// Validation message
44// {
45// data: ...
46// pass: ...
47// error: ...
48// }
49// Creates a new validation message in a uniform way.
50const newMessage = (data, pass, error) => ({
51 // The input data
52 data,
53 // Has the data passed validation?
54 pass,
55 // If data has failed a validator, the error message goes here.
56 error,
57});
59// A validator that always passes.
60export const kDefaultValidator = data => newMessage(data, true, null);
62// Validates a bip39 mnemonic
63export const validateMnemonic = m =>
64 simpleValidatorWrapper({
65 prevMessage: m,
66 validator: d => bip39.validateMnemonic(d),
67 error: 'This is not a valid mnemonic.',
68 });
70// Checks an empty field
71export const validateNotEmpty = m =>
72 simpleValidatorWrapper({
73 prevMessage: m,
74 validator: d => {
75 try {
76 return d.length > 1;
77 } catch {
78 return false;
79 }
80 },
81 error: 'This field is required.',
82 });
84// Checks if a patp is a valid galaxy
85export const validateGalaxy = m =>
86 simpleValidatorWrapper({
87 prevMessage: m,
88 validator: d => {
89 let point;
90 try {
91 point = patp2dec(d);
92 return point >= 0 && point < 256;
93 } catch (e) {
94 return false;
95 }
96 },
97 error: 'This is not a valid galaxy',
98 });
100export const validatePoint = m =>
101 simpleValidatorWrapper({
102 prevMessage: m,
103 validator: d => {
104 try {
105 return ob.isValidPatp(d);
106 } catch (e) {
107 return false;
108 }
109 },
110 error: 'This is not a valid point',
111 });
113export const validateTicket = m =>
114 simpleValidatorWrapper({
115 prevMessage: m,
116 validator: d => {
117 try {
118 return ob.isValidPatq(d);
119 } catch (e) {
120 return false;
121 }
122 },
123 error: 'This is not a valid ticket',
124 });
126export const validateShard = m =>
127 simpleValidatorWrapper({
128 prevMessage: m,
129 validator: d => {
130 try {
131 return ob.isValidPatq(d);
132 } catch (e) {
133 return false;
134 }
135 },
136 error: 'This is not a valid shard',
137 });
139export const validateLength = l => m =>
140 simpleValidatorWrapper({
141 prevMessage: m,
142 validator: d => {
143 try {
144 return d.length === l;
145 } catch {
146 return false;
147 }
148 },
149 error: `Must be exactly ${l} characters`,
150 });
152export const validateHexString = m =>
153 simpleValidatorWrapper({
154 prevMessage: m,
155 validator: d => isHexString.test(d),
156 error: 'This is not a valid hex string',
157 });
159// @deprecate
160export const validateNetworkKey = m =>
161 simpleValidatorWrapper({
162 prevMessage: m,
163 validator: d => plain64CharHexValue.test(d),
164 error: 'This is not a valid network key',
165 });
167// @deprecate
168export const validateNetworkSeed = m =>
169 simpleValidatorWrapper({
170 prevMessage: m,
171 validator: d => plain64CharHexValue.test(d),
172 error: 'This is not a valid network seed',
173 });
175// Checks if a string is a valid ethereum address
176export const validateEthereumAddress = m =>
177 simpleValidatorWrapper({
178 prevMessage: m,
179 validator: d => isValidAddress(d),
180 error: 'This is not a valid Ethereum address',
181 });
183export const validateEmail = m =>
184 simpleValidatorWrapper({
185 prevMessage: m,
186 validator: d => emailRegExp.test(d),
187 error: 'This is not a valid email address',
188 });
190export const validateInt = m =>
191 simpleValidatorWrapper({
192 prevMessage: m,
193 transform: d => parseInt(d, 10),
194 validator: d => {
195 try {
196 parseInt(d, 10);
197 return;
198 } catch {
199 return false;
200 }
201 },
202 error: 'This is not a valid number',
203 });
205export const validateExactly = (value, error) => m =>
206 simpleValidatorWrapper({
207 prevMessage: m,
208 validator: d => d === value,
209 error,
210 });