Skip to content

Commit 8b02b7f

Browse files
authored
Merge branch 'master' into isBefore-options-refactor
2 parents b490cbe + 7ff247d commit 8b02b7f

File tree

7 files changed

+542
-261
lines changed

7 files changed

+542
-261
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Validator | Description
9393
**isAscii(str)** | check if the string contains ASCII chars only.
9494
**isBase32(str [, options])** | check if the string is base32 encoded. `options` is optional and defaults to `{ crockford: false }`.<br/> When `crockford` is true it tests the given base32 encoded string using [Crockford's base32 alternative][Crockford Base32].
9595
**isBase58(str)** | check if the string is base58 encoded.
96-
**isBase64(str [, options])** | check if the string is base64 encoded. `options` is optional and defaults to `{ urlSafe: false }`<br/> when `urlSafe` is true it tests the given base64 encoded string is [url safe][Base64 URL Safe].
96+
**isBase64(str [, options])** | check if the string is base64 encoded. `options` is optional and defaults to `{ urlSafe: false, padding: true }`<br/> when `urlSafe` is true default value for `padding` is false and it tests the given base64 encoded string is [url safe][Base64 URL Safe].
9797
**isBefore(str [, options])** | check if the string is a date that is before the specified date.<br/><br/>`options` is an object that defaults to `{ comparisonDate: Date().toString() }`.<br/><br/>**Options:**<br/>`comparisonDate`: Date to compare to. Defaults to `Date().toString()` (now).
9898
**isBIC(str)** | check if the string is a BIC (Bank Identification Code) or SWIFT code.
9999
**isBoolean(str [, options])** | check if the string is a boolean.<br/>`options` is an object which defaults to `{ loose: false }`. If `loose` is set to false, the validator will strictly match ['true', 'false', '0', '1']. If `loose` is set to true, the validator will also match 'yes', 'no', and will match a valid boolean string of any case. (e.g.: ['true', 'True', 'TRUE']).
@@ -123,7 +123,7 @@ Validator | Description
123123
**isIMEI(str [, options]))** | check if the string is a valid [IMEI number][IMEI]. IMEI should be of format `###############` or `##-######-######-#`.<br/><br/>`options` is an object which can contain the keys `allow_hyphens`. Defaults to first format. If `allow_hyphens` is set to true, the validator will validate the second format.
124124
**isIn(str, values)** | check if the string is in an array of allowed values.
125125
**isInt(str [, options])** | check if the string is an integer.<br/><br/>`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4).
126-
**isIP(str [, version])** | check if the string is an IP (version 4 or 6).
126+
**isIP(str [, options])** | check if the string is an IP address (version 4 or 6).<br/><br/>`options` is an object that defaults to `{ version: '' }`.<br/><br/>**Options:**<br/>`version`: defines which IP version to compare to. Accepted values: `4`, `6`, `'4'`, `'6'`.
127127
**isIPRange(str [, version])** | check if the string is an IP Range (version 4 or 6).
128128
**isISBN(str [, options])** | check if the string is an [ISBN][ISBN].<br/><br/>`options` is an object that has no default.<br/>**Options:**<br/>`version`: ISBN version to compare to. Accepted values are '10' and '13'. If none provided, both will be tested.
129129
**isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier).

src/lib/isBase64.js

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,23 @@
11
import assertString from './util/assertString';
22
import merge from './util/merge';
33

4-
const notBase64 = /[^A-Z0-9+\/=]/i;
5-
const urlSafeBase64 = /^[A-Z0-9_\-]*$/i;
6-
7-
const defaultBase64Options = {
8-
urlSafe: false,
9-
};
4+
const base64WithPadding = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;
5+
const base64WithoutPadding = /^[A-Za-z0-9+/]+$/;
6+
const base64UrlWithPadding = /^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2}==|[A-Za-z0-9_-]{3}=|[A-Za-z0-9_-]{4})$/;
7+
const base64UrlWithoutPadding = /^[A-Za-z0-9_-]+$/;
108

119
export default function isBase64(str, options) {
1210
assertString(str);
13-
options = merge(options, defaultBase64Options);
14-
const len = str.length;
11+
options = merge(options, { urlSafe: false, padding: !options?.urlSafe });
1512

16-
if (options.urlSafe) {
17-
return urlSafeBase64.test(str);
18-
}
13+
if (str === '') return true;
1914

20-
if (len % 4 !== 0 || notBase64.test(str)) {
21-
return false;
15+
let regex;
16+
if (options.urlSafe) {
17+
regex = options.padding ? base64UrlWithPadding : base64UrlWithoutPadding;
18+
} else {
19+
regex = options.padding ? base64WithPadding : base64WithoutPadding;
2220
}
2321

24-
const firstPaddingChar = str.indexOf('=');
25-
return firstPaddingChar === -1 ||
26-
firstPaddingChar === len - 1 ||
27-
(firstPaddingChar === len - 2 && str[len - 1] === '=');
22+
return (!options.padding || str.length % 4 === 0) && regex.test(str);
2823
}

src/lib/isIP.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,24 @@ const IPv6AddressRegExp = new RegExp('^(' +
4444
`(?::((?::${IPv6SegmentFormat}){0,5}:${IPv4AddressFormat}|(?::${IPv6SegmentFormat}){1,7}|:))` +
4545
')(%[0-9a-zA-Z-.:]{1,})?$');
4646

47-
export default function isIP(str, version = '') {
48-
assertString(str);
49-
version = String(version);
47+
export default function isIP(ipAddress, options = {}) {
48+
assertString(ipAddress);
49+
50+
// accessing 'arguments' for backwards compatibility: isIP(ipAddress [, version])
51+
// eslint-disable-next-line prefer-rest-params
52+
const version = (typeof options === 'object' ? options.version : arguments[1]) || '';
53+
5054
if (!version) {
51-
return isIP(str, 4) || isIP(str, 6);
55+
return isIP(ipAddress, { version: 4 }) || isIP(ipAddress, { version: 6 });
5256
}
53-
if (version === '4') {
54-
return IPv4AddressRegExp.test(str);
57+
58+
if (version.toString() === '4') {
59+
return IPv4AddressRegExp.test(ipAddress);
5560
}
56-
if (version === '6') {
57-
return IPv6AddressRegExp.test(str);
61+
62+
if (version.toString() === '6') {
63+
return IPv6AddressRegExp.test(ipAddress);
5864
}
65+
5966
return false;
6067
}

src/lib/isPassportNumber.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const passportRegexByCountryCode = {
1616
BG: /^\d{9}$/, // BULGARIA
1717
BR: /^[A-Z]{2}\d{6}$/, // BRAZIL
1818
BY: /^[A-Z]{2}\d{7}$/, // BELARUS
19-
CA: /^[A-Z]{2}\d{6}$/, // CANADA
19+
CA: /^[A-Z]{2}\d{6}$|^[A-Z]\d{6}[A-Z]{2}$/, // CANADA
2020
CH: /^[A-Z]\d{7}$/, // SWITZERLAND
2121
CN: /^G\d{8}$|^E(?![IO])[A-Z0-9]\d{7}$/, // CHINA [G=Ordinary, E=Electronic] followed by 8-digits, or E followed by any UPPERCASE letter (except I and O) followed by 7 digits
2222
CY: /^[A-Z](\d{6}|\d{8})$/, // CYPRUS

test/validators.test.js

Lines changed: 9 additions & 233 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import assert from 'assert';
22
import fs from 'fs';
33
import timezone_mock from 'timezone-mock';
4-
import { format } from 'util';
54
import vm from 'vm';
6-
import validator from '../src/index';
75
import test from './testFunctions';
86

97
let validator_js = fs.readFileSync(require.resolve('../validator.js')).toString();
@@ -1047,136 +1045,6 @@ describe('Validators', () => {
10471045
});
10481046
});
10491047

1050-
it('should validate IP addresses', () => {
1051-
test({
1052-
validator: 'isIP',
1053-
valid: [
1054-
'127.0.0.1',
1055-
'0.0.0.0',
1056-
'255.255.255.255',
1057-
'1.2.3.4',
1058-
'::1',
1059-
'2001:db8:0000:1:1:1:1:1',
1060-
'2001:db8:3:4::192.0.2.33',
1061-
'2001:41d0:2:a141::1',
1062-
'::ffff:127.0.0.1',
1063-
'::0000',
1064-
'0000::',
1065-
'1::',
1066-
'1111:1:1:1:1:1:1:1',
1067-
'fe80::a6db:30ff:fe98:e946',
1068-
'::',
1069-
'::8',
1070-
'::ffff:127.0.0.1',
1071-
'::ffff:255.255.255.255',
1072-
'::ffff:0:255.255.255.255',
1073-
'::2:3:4:5:6:7:8',
1074-
'::255.255.255.255',
1075-
'0:0:0:0:0:ffff:127.0.0.1',
1076-
'1:2:3:4:5:6:7::',
1077-
'1:2:3:4:5:6::8',
1078-
'1::7:8',
1079-
'1:2:3:4:5::7:8',
1080-
'1:2:3:4:5::8',
1081-
'1::6:7:8',
1082-
'1:2:3:4::6:7:8',
1083-
'1:2:3:4::8',
1084-
'1::5:6:7:8',
1085-
'1:2:3::5:6:7:8',
1086-
'1:2:3::8',
1087-
'1::4:5:6:7:8',
1088-
'1:2::4:5:6:7:8',
1089-
'1:2::8',
1090-
'1::3:4:5:6:7:8',
1091-
'1::8',
1092-
'fe80::7:8%eth0',
1093-
'fe80::7:8%1',
1094-
'64:ff9b::192.0.2.33',
1095-
'0:0:0:0:0:0:10.0.0.1',
1096-
],
1097-
invalid: [
1098-
'abc',
1099-
'256.0.0.0',
1100-
'0.0.0.256',
1101-
'26.0.0.256',
1102-
'0200.200.200.200',
1103-
'200.0200.200.200',
1104-
'200.200.0200.200',
1105-
'200.200.200.0200',
1106-
'::banana',
1107-
'banana::',
1108-
'::1banana',
1109-
'::1::',
1110-
'1:',
1111-
':1',
1112-
':1:1:1::2',
1113-
'1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1',
1114-
'::11111',
1115-
'11111:1:1:1:1:1:1:1',
1116-
'2001:db8:0000:1:1:1:1::1',
1117-
'0:0:0:0:0:0:ffff:127.0.0.1',
1118-
'0:0:0:0:ffff:127.0.0.1',
1119-
],
1120-
});
1121-
test({
1122-
validator: 'isIP',
1123-
args: [4],
1124-
valid: [
1125-
'127.0.0.1',
1126-
'0.0.0.0',
1127-
'255.255.255.255',
1128-
'1.2.3.4',
1129-
'255.0.0.1',
1130-
'0.0.1.1',
1131-
],
1132-
invalid: [
1133-
'::1',
1134-
'2001:db8:0000:1:1:1:1:1',
1135-
'::ffff:127.0.0.1',
1136-
'137.132.10.01',
1137-
'0.256.0.256',
1138-
'255.256.255.256',
1139-
],
1140-
});
1141-
test({
1142-
validator: 'isIP',
1143-
args: [6],
1144-
valid: [
1145-
'::1',
1146-
'2001:db8:0000:1:1:1:1:1',
1147-
'::ffff:127.0.0.1',
1148-
'fe80::1234%1',
1149-
'ff08::9abc%10',
1150-
'ff08::9abc%interface10',
1151-
'ff02::5678%pvc1.3',
1152-
],
1153-
invalid: [
1154-
'127.0.0.1',
1155-
'0.0.0.0',
1156-
'255.255.255.255',
1157-
'1.2.3.4',
1158-
'::ffff:287.0.0.1',
1159-
'%',
1160-
'fe80::1234%',
1161-
'fe80::1234%1%3%4',
1162-
'fe80%fe80%',
1163-
],
1164-
});
1165-
test({
1166-
validator: 'isIP',
1167-
args: [10],
1168-
valid: [],
1169-
invalid: [
1170-
'127.0.0.1',
1171-
'0.0.0.0',
1172-
'255.255.255.255',
1173-
'1.2.3.4',
1174-
'::1',
1175-
'2001:db8:0000:1:1:1:1:1',
1176-
],
1177-
});
1178-
});
1179-
11801048
it('should validate isIPRange', () => {
11811049
test({
11821050
validator: 'isIPRange',
@@ -1371,6 +1239,7 @@ describe('Validators', () => {
13711239
],
13721240
});
13731241
});
1242+
13741243
it('should validate alpha strings', () => {
13751244
test({
13761245
validator: 'isAlpha',
@@ -3085,9 +2954,17 @@ describe('Validators', () => {
30852954
valid: [
30862955
'GA302922',
30872956
'ZE000509',
2957+
'A123456AB',
2958+
'Z556378HG',
30882959
],
30892960
invalid: [
30902961
'AB0123456',
2962+
'AZ556378H',
2963+
'556378HCX',
2964+
'556378432',
2965+
'5563784',
2966+
'#B12345FD',
2967+
'A43F12354',
30912968
],
30922969
});
30932970

@@ -7111,76 +6988,6 @@ describe('Validators', () => {
71116988
});
71126989
});
71136990

7114-
it('should validate base64 strings', () => {
7115-
test({
7116-
validator: 'isBase64',
7117-
valid: [
7118-
'',
7119-
'Zg==',
7120-
'Zm8=',
7121-
'Zm9v',
7122-
'Zm9vYg==',
7123-
'Zm9vYmE=',
7124-
'Zm9vYmFy',
7125-
'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=',
7126-
'Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==',
7127-
'U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==',
7128-
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw' +
7129-
'UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye' +
7130-
'rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619' +
7131-
'FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx' +
7132-
'QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ' +
7133-
'Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ' +
7134-
'HQIDAQAB',
7135-
],
7136-
invalid: [
7137-
'12345',
7138-
'Vml2YW11cyBmZXJtZtesting123',
7139-
'Zg=',
7140-
'Z===',
7141-
'Zm=8',
7142-
'=m9vYg==',
7143-
'Zm9vYmFy====',
7144-
],
7145-
});
7146-
7147-
test({
7148-
validator: 'isBase64',
7149-
args: [{ urlSafe: true }],
7150-
valid: [
7151-
'',
7152-
'bGFkaWVzIGFuZCBnZW50bGVtZW4sIHdlIGFyZSBmbG9hdGluZyBpbiBzcGFjZQ',
7153-
'1234',
7154-
'bXVtLW5ldmVyLXByb3Vk',
7155-
'PDw_Pz8-Pg',
7156-
'VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw',
7157-
],
7158-
invalid: [
7159-
' AA',
7160-
'\tAA',
7161-
'\rAA',
7162-
'\nAA',
7163-
'This+isa/bad+base64Url==',
7164-
'0K3RgtC+INC30LDQutC+0LTQuNGA0L7QstCw0L3QvdCw0Y8g0YHRgtGA0L7QutCw',
7165-
],
7166-
error: [
7167-
null,
7168-
undefined,
7169-
{},
7170-
[],
7171-
42,
7172-
],
7173-
});
7174-
7175-
for (let i = 0, str = '', encoded; i < 1000; i++) {
7176-
str += String.fromCharCode(Math.random() * 26 | 97); // eslint-disable-line no-bitwise
7177-
encoded = Buffer.from(str).toString('base64');
7178-
if (!validator.isBase64(encoded)) {
7179-
let msg = format('validator.isBase64() failed with "%s"', encoded);
7180-
throw new Error(msg);
7181-
}
7182-
}
7183-
});
71846991

71856992
it('should validate hex-encoded MongoDB ObjectId', () => {
71866993
test({
@@ -13826,37 +13633,6 @@ describe('Validators', () => {
1382613633
});
1382713634
});
1382813635

13829-
it('should validate base64URL', () => {
13830-
test({
13831-
validator: 'isBase64',
13832-
args: [{ urlSafe: true }],
13833-
valid: [
13834-
'',
13835-
'bGFkaWVzIGFuZCBnZW50bGVtZW4sIHdlIGFyZSBmbG9hdGluZyBpbiBzcGFjZQ',
13836-
'1234',
13837-
'bXVtLW5ldmVyLXByb3Vk',
13838-
'PDw_Pz8-Pg',
13839-
'VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw',
13840-
],
13841-
invalid: [
13842-
' AA',
13843-
'\tAA',
13844-
'\rAA',
13845-
'\nAA',
13846-
'123=',
13847-
'This+isa/bad+base64Url==',
13848-
'0K3RgtC+INC30LDQutC+0LTQuNGA0L7QstCw0L3QvdCw0Y8g0YHRgtGA0L7QutCw',
13849-
],
13850-
error: [
13851-
null,
13852-
undefined,
13853-
{},
13854-
[],
13855-
42,
13856-
],
13857-
});
13858-
});
13859-
1386013636
it('should validate date', () => {
1386113637
test({
1386213638
validator: 'isDate',

0 commit comments

Comments
 (0)