Skip to content

Commit 86911d8

Browse files
weikangchiarubiin
andauthored
feat(isEmail): allow regexp in host_whitelist and host_blacklist (#2494)
* enhance isEmail to have regexp for host_whitelist * update README.md * refactor code * update test name * fix code logic for checkHost --------- Co-authored-by: Rubin Bhandari <[email protected]>
1 parent f54599c commit 86911d8

File tree

5 files changed

+56
-18
lines changed

5 files changed

+56
-18
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Validator | Description
106106
**isDecimal(str [, options])** | check if the string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.<br/><br/>`options` is an object which defaults to `{force_decimal: false, decimal_digits: '1,', locale: 'en-US'}`.<br/><br/>`locale` determines the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'eo', 'es-ES', 'fa', 'fa-AF', 'fa-IR', 'fr-FR', 'fr-CA', 'hu-HU', 'id-ID', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pl-Pl', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN']`.<br/>**Note:** `decimal_digits` is given as a range like '1,3', a specific value like '3' or min like '1,'.
107107
**isDivisibleBy(str, number)** | check if the string is a number that is divisible by another.
108108
**isEAN(str)** | check if the string is an [EAN (European Article Number)][European Article Number].
109-
**isEmail(str [, options])** | check if the string is an email.<br/><br/>`options` is an object which defaults to `{ allow_display_name: false, require_display_name: false, allow_utf8_local_part: true, require_tld: true, allow_ip_domain: false, allow_underscores: false, domain_specific_validation: false, blacklisted_chars: '', host_blacklist: [] }`. If `allow_display_name` is set to true, the validator will also match `Display Name <email-address>`. If `require_display_name` is set to true, the validator will reject strings without the format `Display Name <email-address>`. If `allow_utf8_local_part` is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If `require_tld` is set to false, email addresses without a TLD in their domain will also be matched. If `ignore_max_length` is set to true, the validator will not check for the standard max length of an email. If `allow_ip_domain` is set to true, the validator will allow IP addresses in the host part. If `domain_specific_validation` is true, some additional validation will be enabled, e.g. disallowing certain syntactically valid email addresses that are rejected by Gmail. If `blacklisted_chars` receives a string, then the validator will reject emails that include any of the characters in the string, in the name part. If `host_blacklist` is set to an array of strings and the part of the email after the `@` symbol matches one of the strings defined in it, the validation fails. If `host_whitelist` is set to an array of strings and the part of the email after the `@` symbol matches none of the strings defined in it, the validation fails.
109+
**isEmail(str [, options])** | check if the string is an email.<br/><br/>`options` is an object which defaults to `{ allow_display_name: false, require_display_name: false, allow_utf8_local_part: true, require_tld: true, allow_ip_domain: false, allow_underscores: false, domain_specific_validation: false, blacklisted_chars: '', host_blacklist: [] }`. If `allow_display_name` is set to true, the validator will also match `Display Name <email-address>`. If `require_display_name` is set to true, the validator will reject strings without the format `Display Name <email-address>`. If `allow_utf8_local_part` is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If `require_tld` is set to false, email addresses without a TLD in their domain will also be matched. If `ignore_max_length` is set to true, the validator will not check for the standard max length of an email. If `allow_ip_domain` is set to true, the validator will allow IP addresses in the host part. If `domain_specific_validation` is true, some additional validation will be enabled, e.g. disallowing certain syntactically valid email addresses that are rejected by Gmail. If `blacklisted_chars` receives a string, then the validator will reject emails that include any of the characters in the string, in the name part. If `host_blacklist` is set to an array of strings or regexp, and the part of the email after the `@` symbol matches one of the strings defined in it, the validation fails. If `host_whitelist` is set to an array of strings or regexp, and the part of the email after the `@` symbol matches none of the strings defined in it, the validation fails.
110110
**isEmpty(str [, options])** | check if the string has a length of zero.<br/><br/>`options` is an object which defaults to `{ ignore_whitespace: false }`.
111111
**isEthereumAddress(str)** | check if the string is an [Ethereum][Ethereum] address. Does not validate address checksums.
112112
**isFloat(str [, options])** | check if the string is a float.<br/><br/>`options` is an object which can contain the keys `min`, `max`, `gt`, and/or `lt` to validate the float is within boundaries (e.g. `{ min: 7.22, max: 9.55 }`) it also has `locale` as an option.<br/><br/>`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.<br/><br/>`locale` determines the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'eo', 'es-ES', 'fr-CA', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. Locale list is `validator.isFloatLocales`.

src/lib/isEmail.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assertString from './util/assertString';
2+
import checkHost from './util/checkHost';
23

34
import isByteLength from './isByteLength';
45
import isFQDN from './isFQDN';
@@ -60,7 +61,6 @@ function validateDisplayName(display_name) {
6061
return true;
6162
}
6263

63-
6464
export default function isEmail(str, options) {
6565
assertString(str);
6666
options = merge(options, default_email_options);
@@ -97,11 +97,11 @@ export default function isEmail(str, options) {
9797
const domain = parts.pop();
9898
const lower_domain = domain.toLowerCase();
9999

100-
if (options.host_blacklist.includes(lower_domain)) {
100+
if (options.host_blacklist.length > 0 && checkHost(lower_domain, options.host_blacklist)) {
101101
return false;
102102
}
103103

104-
if (options.host_whitelist.length > 0 && !options.host_whitelist.includes(lower_domain)) {
104+
if (options.host_whitelist.length > 0 && !checkHost(lower_domain, options.host_whitelist)) {
105105
return false;
106106
}
107107

src/lib/isURL.js

+1-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assertString from './util/assertString';
2+
import checkHost from './util/checkHost';
23

34
import isFQDN from './isFQDN';
45
import isIP from './isIP';
@@ -38,20 +39,6 @@ const default_url_options = {
3839

3940
const wrapped_ipv6 = /^\[([^\]]+)\](?::([0-9]+))?$/;
4041

41-
function isRegExp(obj) {
42-
return Object.prototype.toString.call(obj) === '[object RegExp]';
43-
}
44-
45-
function checkHost(host, matches) {
46-
for (let i = 0; i < matches.length; i++) {
47-
let match = matches[i];
48-
if (host === match || (isRegExp(match) && match.test(host))) {
49-
return true;
50-
}
51-
}
52-
return false;
53-
}
54-
5542
export default function isURL(url, options) {
5643
assertString(url);
5744
if (!url || /[\s<>]/.test(url)) {

src/lib/util/checkHost.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function isRegExp(obj) {
2+
return Object.prototype.toString.call(obj) === '[object RegExp]';
3+
}
4+
5+
export default function checkHost(host, matches) {
6+
for (let i = 0; i < matches.length; i++) {
7+
let match = matches[i];
8+
if (host === match || (isRegExp(match) && match.test(host))) {
9+
return true;
10+
}
11+
}
12+
return false;
13+
}

test/validators.test.js

+38
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,25 @@ describe('Validators', () => {
325325
});
326326
});
327327

328+
it('should allow regular expressions in the host blacklist of isEmail', () => {
329+
test({
330+
validator: 'isEmail',
331+
args: [{
332+
host_blacklist: ['bar.com', 'foo.com', /\.foo\.com$/],
333+
}],
334+
valid: [
335+
336+
337+
338+
],
339+
invalid: [
340+
341+
342+
343+
],
344+
});
345+
});
346+
328347
it('should validate only email addresses with whitelisted domains', () => {
329348
test({
330349
validator: 'isEmail',
@@ -341,6 +360,25 @@ describe('Validators', () => {
341360
});
342361
});
343362

363+
it('should allow regular expressions in the host whitelist of isEmail', () => {
364+
test({
365+
validator: 'isEmail',
366+
args: [{
367+
host_whitelist: ['bar.com', 'foo.com', /\.foo\.com$/],
368+
}],
369+
valid: [
370+
371+
372+
373+
],
374+
invalid: [
375+
376+
377+
378+
],
379+
});
380+
});
381+
344382
it('should validate URLs', () => {
345383
test({
346384
validator: 'isURL',

0 commit comments

Comments
 (0)