Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: isEmail: validate display name using standards of RFC2822 #1004

Merged
merged 3 commits into from
May 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions src/lib/isEmail.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const default_email_options = {

/* eslint-disable max-len */
/* eslint-disable no-control-regex */
const displayName = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\,\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\s]*<(.+)>$/i;
const splitNameAddress = /^([^\x00-\x1F\x7F-\x9F\cX]+)<(.+)>$/i;
const emailUserPart = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i;
const gmailUserPart = /^[a-z\d]+$/;
const quotedEmailUser = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i;
Expand All @@ -23,14 +23,60 @@ const quotedEmailUserUtf8 = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5
/* eslint-enable max-len */
/* eslint-enable no-control-regex */

/**
* Validate display name according to the RFC2822: https://tools.ietf.org/html/rfc2822#appendix-A.1.2
* @param {String} display_name
*/
function validateDisplayName(display_name) {
const trim_quotes = display_name.match(/^"(.+)"$/i);
const display_name_without_quotes = trim_quotes ? trim_quotes[1] : display_name;

// display name with only spaces is not valid
if (!display_name_without_quotes.trim()) {
return false;
}

// check whether display name contains illegal character
const contains_illegal = /[\.";<>]/.test(display_name_without_quotes);
if (contains_illegal) {
// if contains illegal characters,
// must to be enclosed in double-quotes, otherwise it's not a valid display name
if (!trim_quotes) {
return false;
}

// the quotes in display name must start with character symbol \
const all_start_with_back_slash =
display_name_without_quotes.split('"').length === display_name_without_quotes.split('\\"').length;
if (!all_start_with_back_slash) {
return false;
}
}

return true;
}


export default function isEmail(str, options) {
assertString(str);
options = merge(options, default_email_options);

if (options.require_display_name || options.allow_display_name) {
const display_email = str.match(displayName);
const display_email = str.match(splitNameAddress);
if (display_email) {
str = display_email[1];
let display_name;
[, display_name, str] = display_email;
// sometimes need to trim the last space to get the display name
// because there may be a space between display name and email address
// eg. myname <address@gmail.com>
// the display name is `myname` instead of `myname `, so need to trim the last space
if (display_name.endsWith(' ')) {
display_name = display_name.substr(0, display_name.length - 1);
}

if (!validateDisplayName(display_name)) {
return false;
}
} else if (options.require_display_name) {
return false;
}
Expand Down
14 changes: 14 additions & 0 deletions test/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ describe('Validators', () => {
'Name <some.name.midd.leNa.me+extension@GoogleMail.com>',
'Name<some.name.midd.leNa.me+extension@GoogleMail.com>',
'Some Name <foo@gmail.com>',
'Name🍓With🍑Emoji🚴‍♀️🏆<test@aftership.com>',
'🍇🍗🍑<only_emoji@aftership.com>',
'"<displayNameInBrackets>"<jh@gmail.com>',
'"\\"quotes\\""<jh@gmail.com>',
'"name;"<jh@gmail.com>',
'"name;" <jh@gmail.com>',
],
invalid: [
'invalidemail@',
Expand All @@ -195,6 +201,14 @@ describe('Validators', () => {
'Some Name < foo@bar.co.uk >',
'Name foo@bar.co.uk',
'Some Name <some..name@gmail.com>',
'Some Name<emoji_in_address🍈@aftership.com>',
'invisibleCharacter\u001F<jh@gmail.com>',
'<displayNameInBrackets><jh@gmail.com>',
'\\"quotes\\"<jh@gmail.com>',
'""quotes""<jh@gmail.com>',
'name;<jh@gmail.com>',
' <jh@gmail.com>',
'" "<jh@gmail.com>',
],
});
});
Expand Down