-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite as a recursive descent parser
This simplifies some of our validation, and opens the door to let users of the module run their own DNS check through a general-purpose API.
- Loading branch information
Showing
8 changed files
with
1,687 additions
and
1,312 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
'use strict'; | ||
|
||
exports.categories = { | ||
valid: 1, | ||
dnsWarn: 7, | ||
rfc5321: 15, | ||
cfws: 31, | ||
deprecated: 63, | ||
rfc5322: 127, | ||
error: 255 | ||
}; | ||
|
||
exports.diagnoses = { | ||
|
||
// Address is valid | ||
|
||
valid: 0, | ||
|
||
// Address is valid for SMTP but has unusual elements | ||
|
||
rfc5321TLD: 9, | ||
rfc5321TLDNumeric: 10, | ||
rfc5321QuotedString: 11, | ||
rfc5321AddressLiteral: 12, | ||
|
||
// Address is valid for message, but must be modified for envelope | ||
|
||
cfwsComment: 17, | ||
cfwsFWS: 18, | ||
|
||
// Address contains non-ASCII when the allowUnicode option is false | ||
// Has to be > internals.defaultThreshold so that it's rejected | ||
// without an explicit errorLevel: | ||
undesiredNonAscii: 25, | ||
|
||
// Address contains deprecated elements, but may still be valid in some contexts | ||
|
||
deprecatedLocalPart: 33, | ||
deprecatedFWS: 34, | ||
deprecatedQTEXT: 35, | ||
deprecatedQP: 36, | ||
deprecatedComment: 37, | ||
deprecatedCTEXT: 38, | ||
deprecatedIPv6: 39, | ||
deprecatedCFWSNearAt: 49, | ||
|
||
// Address is only valid according to broad definition in RFC 5322, but is otherwise invalid | ||
|
||
rfc5322Domain: 65, | ||
rfc5322TooLong: 66, | ||
rfc5322LocalTooLong: 67, | ||
rfc5322DomainTooLong: 68, | ||
rfc5322LabelTooLong: 69, | ||
rfc5322DomainLiteral: 70, | ||
rfc5322DomainLiteralOBSDText: 71, | ||
rfc5322IPv6GroupCount: 72, | ||
rfc5322IPv62x2xColon: 73, | ||
rfc5322IPv6BadCharacter: 74, | ||
rfc5322IPv6MaxGroups: 75, | ||
rfc5322IPv6ColonStart: 76, | ||
rfc5322IPv6ColonEnd: 77, | ||
|
||
// Address is invalid for any purpose | ||
|
||
errExpectingDTEXT: 129, | ||
errNoLocalPart: 130, | ||
errNoDomain: 131, | ||
errConsecutiveDots: 132, | ||
errATEXTAfterCFWS: 133, | ||
errATEXTAfterQS: 134, | ||
errATEXTAfterDomainLiteral: 135, | ||
errExpectingQPair: 136, | ||
errExpectingATEXT: 137, | ||
errExpectingQTEXT: 138, | ||
errExpectingCTEXT: 139, | ||
errBackslashEnd: 140, | ||
errDotStart: 141, | ||
errDotEnd: 142, | ||
errDomainHyphenStart: 143, | ||
errDomainHyphenEnd: 144, | ||
errUnclosedQuotedString: 145, | ||
errUnclosedComment: 146, | ||
errUnclosedDomainLiteral: 147, | ||
errFWSCRLFx2: 148, | ||
errFWSCRLFEnd: 149, | ||
errCRNoLF: 150, | ||
errUnknownTLD: 160, | ||
errDomainTooShort: 161, | ||
errDotAfterDomainLiteral: 162 | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
'use strict'; | ||
|
||
// Load modules | ||
|
||
const Constants = require('./constants'); | ||
|
||
/** | ||
* Diagnosis stores a diagnosis-index pair. | ||
*/ | ||
class Diagnosis { | ||
/** | ||
* @param {number} type The diagnostic code. | ||
* @param {number} index The index of the diagnosis. | ||
*/ | ||
constructor(type, index) { | ||
|
||
this.type = type; | ||
this.index = index; | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Diagnoses tracks a set of diagnostic codes for a string, along with their | ||
* positions in the string. | ||
*/ | ||
class Diagnoses { | ||
constructor() { | ||
|
||
this._diagnoses = []; | ||
this._legacyDiagnosis = null; | ||
this._worstDiagnosis = null; | ||
} | ||
|
||
/** | ||
* Report the given diagnosis at the given index. | ||
* | ||
* @param {number} type The diagnosis to report. | ||
* @param {number} index The | ||
*/ | ||
diagnose(type, index) { | ||
|
||
const diagnosis = new Diagnosis(type, index); | ||
|
||
if (this._worstDiagnosis === null || type > this._worstDiagnosis.type) { | ||
this._worstDiagnosis = diagnosis; | ||
} | ||
|
||
this._diagnoses.push(diagnosis); | ||
} | ||
|
||
/** | ||
* Check whether the given diagnosis has been reported. | ||
* | ||
* @param {number} queryType The diagnosis to query. | ||
* @return {boolean} Whether the diagnosis has been reported. | ||
*/ | ||
hasDiagnosis(queryType) { | ||
|
||
return this._diagnoses.some(({ type }) => type === queryType); | ||
} | ||
|
||
/** | ||
* Get the worst diagnosis encountered. | ||
* | ||
* @return {number} The worst diagnosis. | ||
*/ | ||
getWorstDiagnosis() { | ||
|
||
return this._worstDiagnosis; | ||
} | ||
|
||
/** | ||
* For compatibility with existing versions of isemail, this function gets | ||
* the first fatal diagnosis, or the worst non-fatal diagnosis. | ||
* | ||
* @return {number} The backwards-compatible diagnosis. | ||
*/ | ||
getLegacyDiagnosis() { | ||
|
||
return this._diagnoses.find(({ type }) => type >= Constants.categories.rfc5322) || this._worstDiagnosis; | ||
} | ||
} | ||
|
||
|
||
module.exports = Diagnoses; |
Oops, something went wrong.