Skip to content
This repository has been archived by the owner on Oct 2, 2024. It is now read-only.

Commit

Permalink
[2.1.0] add tldBlacklist option, fixes #9
Browse files Browse the repository at this point in the history
Also add Isemail.diagnoses as an alias for Isemail.validate.diagnoses.

Signed-off-by: Eli Skeggs <[email protected]>
  • Loading branch information
skeggse committed Nov 3, 2015
1 parent 81b754b commit 6e24ff6
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 29 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

* * *

The complete list of contributors can be found at: https://github.com/hapijs/ammo/graphs/contributors
The complete list of contributors can be found at: https://github.com/hapijs/isemail/graphs/contributors
Previously published under the 2-Clause-BSD license published here: https://github.com/hapijs/isemail/blob/v1.2.0/LICENSE

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ Determines whether the `email` is valid or not, for various definitions thereof.

Use `errorLevel` to specify the type of result for `validate()`. Passing a `false` literal will result in a true or false boolean indicating whether the email address is sufficiently defined for use in sending an email. Passing a `true` literal will result in a more granular numeric status, with zero being a perfectly valid email address. Passing a number will return `0` if the numeric status is below the `errorLevel` and the numeric status otherwise.

The `tldBlacklist` option can be either an object lookup table or an array of invalid top-level domains. If the email address has a top-level domain that is in the whitelist, the email will be marked as invalid.

The `tldWhitelist` option can be either an object lookup table or an array of valid top-level domains. If the email address has a top-level domain that is not in the whitelist, the email will be marked as invalid.

Only one of `tldBlacklist` and `tldWhitelist` will be consulted for TLD validity.

The `minDomainAtoms` option is an optional positive integer that specifies the minimum number of domain atoms that must be included for the email address to be considered valid. Be careful with the option, as some top-level domains, like `io`, directly support email addresses. To better handle fringe cases like the `io` TLD, use the `checkDNS` parameter, which will only allow email addresses for domains which have an MX record.

### Examples
Expand Down
61 changes: 37 additions & 24 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const Dns = require('dns');

const internals = {
hasOwn: Object.prototype.hasOwnProperty,
indexOf: Array.prototype.indexOf,
defaultThreshold: 16,
maxIPv6Groups: 8,

Expand Down Expand Up @@ -151,6 +152,24 @@ internals.checkIpV6 = function (items) {
};


internals.validDomain = function (tldAtom, options) {

if (options.tldBlacklist) {
if (Array.isArray(options.tldBlacklist)) {
return internals.indexOf.call(options.tldBlacklist, tldAtom) === -1;
}

return !internals.hasOwn.call(options.tldBlacklist, tldAtom);
}

if (Array.isArray(options.tldWhitelist)) {
return internals.indexOf.call(options.tldWhitelist, tldAtom) !== -1;
}

return internals.hasOwn.call(options.tldWhitelist, tldAtom);
};


/**
* Check that an email address conforms to RFCs 5321, 5322 and others
*
Expand All @@ -159,19 +178,16 @@ internals.checkIpV6 = function (items) {
* regarded as a valid email address. The RFC 5321 Mailbox specification is
* more restrictive (comments, white space and obsolete forms are not allowed).
*
* @param {string} email The email address to check.
* @param {string} email The email address to check. See README for specifics.
* @param {Object} options The (optional) options:
* {boolean} checkDNS If true then will check DNS for MX records. If
* true this call to isEmail _will_ be asynchronous.
* {*} errorLevel Determines the boundary between valid and invalid
* addresses. Status codes above this number will be returned as-is, status
* codes below will be returned as valid. Thus the calling program can
* simply look for diagnoses.valid if it is only interested in whether an
* address is valid or not. The errorLevel will determine how "picky"
* isEmail() is about the address. If omitted or passed as false then
* isEmail() will return true or false rather than an integer error or
* warning. NB Note the difference between errorLevel = false and
* errorLevel = 0.
* addresses.
* {*} tldBlacklist The set of domains to consider invalid.
* {*} tldWhitelist The set of domains to consider valid.
* {*} minDomainAtoms The minimum number of domain atoms which must be present
* for the address to be valid.
* @param {function(number|boolean)} callback The (optional) callback handler.
* @return {*}
*/
Expand Down Expand Up @@ -214,6 +230,15 @@ exports.validate = internals.validate = function (email, options, callback) {
}
}

if (options.tldBlacklist) {
if (typeof options.tldBlacklist === 'string') {
options.tldBlacklist = [options.tldBlacklist];
}
else if (typeof options.tldBlacklist !== 'object') {
throw new TypeError('expected array or object tldBlacklist');
}
}

if (options.minDomainAtoms && (options.minDomainAtoms !== ((+options.minDomainAtoms) | 0) || options.minDomainAtoms < 0)) {
throw new TypeError('expected positive integer minDomainAtoms');
}
Expand Down Expand Up @@ -1223,22 +1248,10 @@ exports.validate = internals.validate = function (email, options, callback) {
else if (options.minDomainAtoms && atomData.domains.length < options.minDomainAtoms) {
updateResult(internals.diagnoses.errDomainTooShort);
}
else if (options.tldWhitelist) {
else if (options.tldWhitelist || options.tldBlacklist) {
const tldAtom = atomData.domains[elementCount];
if (Array.isArray(options.tldWhitelist)) {
let tldValid = false;
for (let i = 0; i < options.tldWhitelist.length; ++i) {
if (tldAtom === options.tldWhitelist[i]) {
tldValid = true;
break;
}
}

if (!tldValid) {
updateResult(internals.diagnoses.errUnknownTLD);
}
}
else if (!internals.hasOwn.call(options.tldWhitelist, tldAtom)) {
if (!internals.validDomain(tldAtom, options)) {
updateResult(internals.diagnoses.errUnknownTLD);
}
}
Expand Down Expand Up @@ -1350,7 +1363,7 @@ exports.validate = internals.validate = function (email, options, callback) {
};


internals.validate.diagnoses = (function () {
exports.diagnoses = internals.validate.diagnoses = (function () {

const diag = {};
const keys = Object.keys(internals.diagnoses);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "isemail",
"description": "Validate an email address according to RFCs 5321, 5322, and others",
"version": "2.0.0",
"version": "2.1.0",
"repository": "git://github.com/hapijs/isemail",
"main": "lib/index.js",
"keywords": [
Expand Down
45 changes: 42 additions & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ describe('validate()', () => {
checkDNS: false
})).to.equal(false);

expect(Isemail.validate('person@top', {
tldWhitelist: { com: true },
checkDNS: false
})).to.equal(false);

expect(() => {

Isemail.validate('', {
Expand All @@ -72,6 +77,32 @@ describe('validate()', () => {
done();
});

it('should check options.tldBlacklist', (done) => {

expect(Isemail.validate('person@top', {
tldBlacklist: 'top',
checkDNS: false
})).to.equal(false);

expect(Isemail.validate('person@top', {
tldBlacklist: ['com'],
checkDNS: false
})).to.equal(true);

expect(Isemail.validate('person@top', {
tldBlacklist: { com: true },
checkDNS: false
})).to.equal(true);

expect(() => {

Isemail.validate('', {
tldBlacklist: 77
});
}).to.throw(/tldBlacklist/);
done();
});

it('should check options.minDomainAtoms', (done) => {

expect(() => {
Expand Down Expand Up @@ -153,16 +184,24 @@ describe('validate()', () => {

expect(Isemail.validate(email, {
errorLevel: 0,
tldWhitelist: {
com: true
}
tldWhitelist: { com: true }
})).to.equal(result);

expect(Isemail.validate(email, {
errorLevel: 0,
tldWhitelist: ['com']
})).to.equal(result);

expect(Isemail.validate(email, {
errorLevel: 0,
tldBlacklist: { invalid: true }
})).to.equal(result);

expect(Isemail.validate(email, {
errorLevel: 0,
tldBlacklist: ['invalid']
})).to.equal(result);

done();
});
});
Expand Down

0 comments on commit 6e24ff6

Please sign in to comment.