Skip to content

Commit f3f5cf7

Browse files
mirabilospetebacondarwin
authored andcommitted
fix(input[email]): improve email address validation
**Limit size of local-part and total path size in eMail addresses** RFC 5321 §4.5.3.1.1 ⇒ local-part can have up to 64 octets RFC 5321 §4.5.3.1.3 ⇒ path “including the punctuation and element separators” can have up to 256 octets RFC 5321 §4.1.2 specifies path as ‘<’ + mailbox¹ + ‘>’ in the best case, leaving us 254 octets The limitation of the total path size to 254 octets leaves at most 252 octets (one local-part, one ‘@’) for the domain, which means we don’t need to explicitly check the domain size any more (removing the assertion after the ‘@’). ① RFC 821/5321 “mailbox” is the same as RFC 822 “addr-spec” **Optimise eMail address regex for speed** There is no need to make it case-insensitive; the local-part already catches the entire range, and the host part is easily done. Furthermore, this makes the regex locale-independent, avoiding issues with e.g. turkish case conversions. cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD **Limit eMail address total host part length** RFC 1035 §2.3.4 imposes a maximum length for any DNS object; RFC 5321 §2.3.5 references this (and requires FQDNs, but there have been cases where a TLD had an MX RR and thus eMail addresses like “localpart@tld” are valid). Credits: Natureshadow <[email protected]> **Limit eMail address individual host part length** A “label” (each of the things between the dots (‘.’) after the ‘@’ in the eMail address) MUST NOT be longer than 63 characters. cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD and RFC 1035 §2.3.4 **Fix eMail address local-part validation** A period (‘.’) may not begin or end a local-part cf. http://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/mailfrom.php?rev=HEAD and RFC 822 / 5321 Closes angular#14719
1 parent 2274dc7 commit f3f5cf7

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

src/ng/directive/input.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
2424
// 9. Fragment
2525
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
2626
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
27-
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
27+
/* jshint maxlen:220 */
28+
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
29+
/* jshint maxlen:200 */
2830
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
2931
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
3032
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;

test/ng/directive/inputSpec.js

+89
Original file line numberDiff line numberDiff line change
@@ -2784,14 +2784,103 @@ describe('input', function() {
27842784
describe('EMAIL_REGEXP', function() {
27852785
/* global EMAIL_REGEXP: false */
27862786
it('should validate email', function() {
2787+
/* basic functionality */
27872788
expect(EMAIL_REGEXP.test('[email protected]')).toBe(true);
27882789
expect(EMAIL_REGEXP.test('[email protected]')).toBe(true);
27892790
expect(EMAIL_REGEXP.test('[email protected]')).toBe(true);
2791+
/* domain label separation, hyphen-minus, syntax */
2792+
expect(EMAIL_REGEXP.test('[email protected].')).toBe(false);
27902793
expect(EMAIL_REGEXP.test('[email protected]')).toBe(false);
27912794
expect(EMAIL_REGEXP.test('[email protected]')).toBe(false);
27922795
expect(EMAIL_REGEXP.test('[email protected]')).toBe(false);
2796+
expect(EMAIL_REGEXP.test('a@b-c')).toBe(true);
2797+
expect(EMAIL_REGEXP.test('a@-')).toBe(false);
2798+
expect(EMAIL_REGEXP.test('a@.')).toBe(false);
2799+
expect(EMAIL_REGEXP.test('a@host_name')).toBe(false);
2800+
/* leading or sole digit */
27932801
expect(EMAIL_REGEXP.test('[email protected]')).toBe(true);
2802+
expect(EMAIL_REGEXP.test('a@3')).toBe(true);
2803+
/* TLD eMail address */
27942804
expect(EMAIL_REGEXP.test('a@b')).toBe(true);
2805+
/* domain valid characters */
2806+
expect(EMAIL_REGEXP.test('a@abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789')).toBe(true);
2807+
/* domain invalid characters */
2808+
expect(EMAIL_REGEXP.test('a@')).toBe(false);
2809+
expect(EMAIL_REGEXP.test('a@ ')).toBe(false);
2810+
expect(EMAIL_REGEXP.test('a@!')).toBe(false);
2811+
expect(EMAIL_REGEXP.test('a@"')).toBe(false);
2812+
expect(EMAIL_REGEXP.test('a@#')).toBe(false);
2813+
expect(EMAIL_REGEXP.test('a@$')).toBe(false);
2814+
expect(EMAIL_REGEXP.test('a@%')).toBe(false);
2815+
expect(EMAIL_REGEXP.test('a@&')).toBe(false);
2816+
expect(EMAIL_REGEXP.test("a@'")).toBe(false);
2817+
expect(EMAIL_REGEXP.test('a@(')).toBe(false);
2818+
expect(EMAIL_REGEXP.test('a@)')).toBe(false);
2819+
expect(EMAIL_REGEXP.test('a@*')).toBe(false);
2820+
expect(EMAIL_REGEXP.test('a@+')).toBe(false);
2821+
expect(EMAIL_REGEXP.test('a@,')).toBe(false);
2822+
expect(EMAIL_REGEXP.test('a@/')).toBe(false);
2823+
expect(EMAIL_REGEXP.test('a@:')).toBe(false);
2824+
expect(EMAIL_REGEXP.test('a@;')).toBe(false);
2825+
expect(EMAIL_REGEXP.test('a@<')).toBe(false);
2826+
expect(EMAIL_REGEXP.test('a@=')).toBe(false);
2827+
expect(EMAIL_REGEXP.test('a@>')).toBe(false);
2828+
expect(EMAIL_REGEXP.test('a@?')).toBe(false);
2829+
expect(EMAIL_REGEXP.test('a@@')).toBe(false);
2830+
expect(EMAIL_REGEXP.test('a@[')).toBe(false);
2831+
expect(EMAIL_REGEXP.test('a@\\')).toBe(false);
2832+
expect(EMAIL_REGEXP.test('a@]')).toBe(false);
2833+
expect(EMAIL_REGEXP.test('a@^')).toBe(false);
2834+
expect(EMAIL_REGEXP.test('a@_')).toBe(false);
2835+
expect(EMAIL_REGEXP.test('a@`')).toBe(false);
2836+
expect(EMAIL_REGEXP.test('a@{')).toBe(false);
2837+
expect(EMAIL_REGEXP.test('a@|')).toBe(false);
2838+
expect(EMAIL_REGEXP.test('a@}')).toBe(false);
2839+
expect(EMAIL_REGEXP.test('a@~')).toBe(false);
2840+
expect(EMAIL_REGEXP.test('a@İ')).toBe(false);
2841+
expect(EMAIL_REGEXP.test('a@ı')).toBe(false);
2842+
/* domain length, label and total */
2843+
expect(EMAIL_REGEXP.test('a@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')).toBe(true);
2844+
expect(EMAIL_REGEXP.test('a@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')).toBe(false);
2845+
/* jshint maxlen:320 */
2846+
expect(EMAIL_REGEXP.test('a@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')).toBe(true);
2847+
expect(EMAIL_REGEXP.test('a@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.x')).toBe(true);
2848+
expect(EMAIL_REGEXP.test('a@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xx')).toBe(false);
2849+
expect(EMAIL_REGEXP.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xx')).toBe(true);
2850+
expect(EMAIL_REGEXP.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxx')).toBe(false);
2851+
/* jshint maxlen:200 */
2852+
/* local-part valid characters and dot-atom syntax */
2853+
expect(EMAIL_REGEXP.test("'@x")).toBe(true);
2854+
expect(EMAIL_REGEXP.test('-!#$%&*+/0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ@x')).toBe(true);
2855+
expect(EMAIL_REGEXP.test('^_`abcdefghijklmnopqrstuvwxyz{|}~@x')).toBe(true);
2856+
expect(EMAIL_REGEXP.test(".@x")).toBe(false);
2857+
expect(EMAIL_REGEXP.test("'.@x")).toBe(false);
2858+
expect(EMAIL_REGEXP.test(".'@x")).toBe(false);
2859+
expect(EMAIL_REGEXP.test("'.'@x")).toBe(true);
2860+
/* local-part invalid characters */
2861+
expect(EMAIL_REGEXP.test('@x')).toBe(false);
2862+
expect(EMAIL_REGEXP.test(' @x')).toBe(false);
2863+
expect(EMAIL_REGEXP.test('"@x')).toBe(false);
2864+
expect(EMAIL_REGEXP.test('(@x')).toBe(false);
2865+
expect(EMAIL_REGEXP.test(')@x')).toBe(false);
2866+
expect(EMAIL_REGEXP.test(',@x')).toBe(false);
2867+
expect(EMAIL_REGEXP.test(':@x')).toBe(false);
2868+
expect(EMAIL_REGEXP.test(';@x')).toBe(false);
2869+
expect(EMAIL_REGEXP.test('<@x')).toBe(false);
2870+
expect(EMAIL_REGEXP.test('>@x')).toBe(false);
2871+
expect(EMAIL_REGEXP.test('@@x')).toBe(false);
2872+
expect(EMAIL_REGEXP.test('[@x')).toBe(false);
2873+
expect(EMAIL_REGEXP.test('\\@x')).toBe(false);
2874+
expect(EMAIL_REGEXP.test(']@x')).toBe(false);
2875+
expect(EMAIL_REGEXP.test('İ@x')).toBe(false);
2876+
expect(EMAIL_REGEXP.test('ı@x')).toBe(false);
2877+
/* local-part size limit */
2878+
expect(EMAIL_REGEXP.test('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@x')).toBe(true);
2879+
expect(EMAIL_REGEXP.test('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@x')).toBe(false);
2880+
/* content (local-part + ‘@’ + domain) is required */
2881+
expect(EMAIL_REGEXP.test('')).toBe(false);
2882+
expect(EMAIL_REGEXP.test('a')).toBe(false);
2883+
expect(EMAIL_REGEXP.test('aa')).toBe(false);
27952884
});
27962885
});
27972886
});

0 commit comments

Comments
 (0)