-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
Copy pathValidationUtils.js
229 lines (203 loc) · 5.19 KB
/
ValidationUtils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import moment from 'moment';
import _ from 'underscore';
import CONST from '../CONST';
/**
* Implements the Luhn Algorithm, a checksum formula used to validate credit card
* numbers.
*
* @param {String} val
* @returns {Boolean}
*/
function validateCardNumber(val) {
let sum = 0;
for (let i = 0; i < val.length; i++) {
let intVal = parseInt(val.substr(i, 1), 10);
if (i % 2 === 0) {
intVal *= 2;
if (intVal > 9) {
intVal = 1 + (intVal % 10);
}
}
sum += intVal;
}
return (sum % 10) === 0;
}
/**
* Validating that this is a valid address (PO boxes are not allowed)
*
* @param {String} value
* @returns {Boolean}
*/
function isValidAddress(value) {
if (!CONST.REGEX.ANY_VALUE.test(value)) {
return false;
}
return !CONST.REGEX.PO_BOX.test(value);
}
/**
* Validate date fields
*
* @param {String|Date} date
* @returns {Boolean} true if valid
*/
function isValidDate(date) {
if (!date) {
return false;
}
const pastDate = moment().subtract(1000, 'years');
const futureDate = moment().add(1000, 'years');
const testDate = moment(date);
return testDate.isValid() && testDate.isBetween(pastDate, futureDate);
}
/**
* Used to validate a value that is "required".
*
* @param {*} value
* @returns {Boolean}
*/
function isRequiredFulfilled(value) {
if (_.isString(value)) {
return !_.isEmpty(value.trim());
}
if (_.isDate(value)) {
return isValidDate(value);
}
if (_.isArray(value) || _.isObject(value)) {
return !_.isEmpty(value);
}
return Boolean(value);
}
/**
* Validates that this is a valid expiration date
* in the MM/YY or MM/YYYY format
*
* @param {String} string
* @returns {Boolean}
*/
function isValidExpirationDate(string) {
return CONST.REGEX.CARD_EXPIRATION_DATE.test(string);
}
/**
* Validates that this is a valid security code
* in the XXX or XXXX format.
*
* @param {String} string
* @returns {Boolean}
*/
function isValidSecurityCode(string) {
return CONST.REGEX.CARD_SECURITY_CODE.test(string);
}
/**
* Validates a debit card number (15 or 16 digits).
*
* @param {String} string
* @returns {Boolean}
*/
function isValidDebitCard(string) {
if (!CONST.REGEX.CARD_NUMBER.test(string)) {
return false;
}
return validateCardNumber(string);
}
/**
* @param {String} code
* @returns {Boolean}
*/
function isValidIndustryCode(code) {
return CONST.REGEX.INDUSTRY_CODE.test(code);
}
/**
* @param {String} zipCode
* @returns {Boolean}
*/
function isValidZipCode(zipCode) {
return CONST.REGEX.ZIP_CODE.test(zipCode);
}
/**
* @param {String} ssnLast4
* @returns {Boolean}
*/
function isValidSSNLastFour(ssnLast4) {
return CONST.REGEX.SSN_LAST_FOUR.test(ssnLast4);
}
/**
* Validate that "date" is between 18 and 150 years in the past
*
* @param {String} date
* @returns {Boolean}
*/
function meetsAgeRequirements(date) {
const eighteenYearsAgo = moment().subtract(18, 'years');
const oneHundredFiftyYearsAgo = moment().subtract(150, 'years');
const testDate = moment(date);
return testDate.isValid() && testDate.isBetween(oneHundredFiftyYearsAgo, eighteenYearsAgo);
}
/**
*
* @param {String} phoneNumber
* @returns {Boolean}
*/
function isValidPhoneWithSpecialChars(phoneNumber) {
return CONST.REGEX.PHONE_WITH_SPECIAL_CHARS.test(phoneNumber) && phoneNumber.length <= CONST.PHONE_MAX_LENGTH && phoneNumber.length >= CONST.PHONE_MIN_LENGTH;
}
/**
* @param {String} url
* @returns {Boolean}
*/
function isValidURL(url) {
return CONST.REGEX.HYPERLINK.test(url);
}
/**
* @param {Object} identity
* @returns {Object}
*/
function validateIdentity(identity) {
const requiredFields = ['firstName', 'lastName', 'street', 'city', 'zipCode', 'state', 'ssnLast4', 'dob'];
const errors = {};
// Check that all required fields are filled
_.each(requiredFields, (fieldName) => {
if (isRequiredFulfilled(identity[fieldName])) {
return;
}
errors[fieldName] = true;
});
if (!isValidAddress(identity.street)) {
errors.street = true;
}
if (!isValidZipCode(identity.zipCode)) {
errors.zipCode = true;
}
// dob field has multiple validations/errors, we are handling it temporarily like this.
if (!isValidDate(identity.dob)) {
errors.dob = true;
} else if (!meetsAgeRequirements(identity.dob)) {
errors.dobAge = true;
}
if (!isValidSSNLastFour(identity.ssnLast4)) {
errors.ssnLast4 = true;
}
return errors;
}
/**
* @param {String} phoneNumber
* @returns {Boolean}
*/
function isValidUSPhone(phoneNumber) {
// Remove alphanumeric characters and validate that this is in fact a phone number
return CONST.REGEX.PHONE_E164_PLUS.test(phoneNumber.replace(CONST.REGEX.NON_ALPHA_NUMERIC, '')) && CONST.REGEX.US_PHONE.test(phoneNumber);
}
export {
meetsAgeRequirements,
isValidAddress,
isValidDate,
isValidSecurityCode,
isValidExpirationDate,
isValidDebitCard,
isValidIndustryCode,
isValidZipCode,
isRequiredFulfilled,
isValidPhoneWithSpecialChars,
isValidUSPhone,
isValidURL,
validateIdentity,
};