fix(client): validate emails against IETF rfc5321
* email must have >= 2 part tld * email can have [1, 64] byte local length * email can have [3, 255] byte domain length * email can be up to 256 bytes long For more info, see http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1 Closes #563
This commit is contained in:
Родитель
ee3618cb8d
Коммит
d7d3a0ba93
|
@ -109,6 +109,13 @@ function (_, $, BaseView, Tooltip) {
|
|||
*/
|
||||
isElementValid: function (selector) {
|
||||
var el = this.$(selector);
|
||||
var type = el.attr('type');
|
||||
|
||||
// email follows our own rules.
|
||||
if (type === 'email') {
|
||||
return this.validateEmail(selector);
|
||||
}
|
||||
|
||||
var value = el.val();
|
||||
var isValid = !!(value && el[0].validity.valid);
|
||||
return isValid;
|
||||
|
@ -183,6 +190,38 @@ function (_, $, BaseView, Tooltip) {
|
|||
showValidationErrorsEnd: function () {
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate an email field
|
||||
*
|
||||
* @return true if email is valid, false otw.
|
||||
*/
|
||||
validateEmail: function (selector) {
|
||||
var email = this.$(selector).val();
|
||||
if (typeof(email) !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parts = email.split('@');
|
||||
|
||||
var localLength = parts[0] && parts[0].length;
|
||||
var domainLength = parts[1] && parts[1].length;
|
||||
|
||||
// Original regexp from:
|
||||
// http://blog.gerv.net/2011/05/html5_email_email_regexp/
|
||||
// Modified to require at least a 2 part tld and remove the
|
||||
// length checks, which are done later.
|
||||
// IETF spec: http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
|
||||
// NOTE: this does *NOT* allow internationalized domain names.
|
||||
return (/^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d][a-z\d\-]*(?:\.[a-z\d][a-z\d\-]*)+$/i).test(email) &&
|
||||
// total email allwed to be 256 bytes long
|
||||
email.length <= 256 &&
|
||||
// local side only allowed to be 64 bytes long
|
||||
1 <= localLength && localLength <= 64 &&
|
||||
// domain side allowed to be up to 255 bytes long which
|
||||
// doesn't make much sense unless the local side has 0 length;
|
||||
3 <= domainLength && domainLength <= 255;
|
||||
},
|
||||
|
||||
showEmailValidationError: function (which) {
|
||||
this.showValidationError(which, t('Valid email required'));
|
||||
},
|
||||
|
|
|
@ -62,6 +62,7 @@ function (chai, _, $, View, Session, FxaClient, RouterMock) {
|
|||
});
|
||||
|
||||
it('returns false if email is empty', function () {
|
||||
$('[type=email]').val('');
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
|
@ -76,6 +77,131 @@ function (chai, _, $, View, Session, FxaClient, RouterMock) {
|
|||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if email contain one part TLD', function () {
|
||||
$('[type=email]').val('a@b');
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns true if email contain two part TLD', function () {
|
||||
$('[type=email]').val('a@b.c');
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isTrue(view.isValid());
|
||||
});
|
||||
|
||||
it('returns true if email contain three part TLD', function () {
|
||||
$('[type=email]').val('a@b.c.d');
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isTrue(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if local side of email === 0 chars', function () {
|
||||
var email = '@testuser.com';
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if local side of email > 64 chars', function () {
|
||||
var email = '';
|
||||
do {
|
||||
email += 'a';
|
||||
} while (email.length < 65);
|
||||
|
||||
email += '@testuser.com';
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns true if local side of email === 64 chars', function () {
|
||||
var email = '';
|
||||
do {
|
||||
email += 'a';
|
||||
} while (email.length < 64);
|
||||
|
||||
email += '@testuser.com';
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isTrue(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if domain side of email === 0 chars', function () {
|
||||
var email = 'testuser@';
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if domain side of email > 255 chars', function () {
|
||||
var domain = 'testuser.com';
|
||||
do {
|
||||
domain += 'a';
|
||||
} while (domain.length < 256);
|
||||
|
||||
var email = 'testuser@' + domain;
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns true if domain side of email === 254 chars', function () {
|
||||
var domain = 'testuser.com';
|
||||
do {
|
||||
domain += 'a';
|
||||
} while (domain.length < 254);
|
||||
var email = 'a@' + domain;
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isTrue(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false total length > 256 chars', function () {
|
||||
var domain = 'testuser.com';
|
||||
do {
|
||||
domain += 'a';
|
||||
} while (domain.length < 254);
|
||||
|
||||
// ab@ + 254 characters = 257 chars
|
||||
var email = 'ab@' + domain;
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isFalse(view.isValid());
|
||||
});
|
||||
|
||||
it('returns true if total length === 256 chars', function () {
|
||||
var email = 'testuser@testuser.com';
|
||||
do {
|
||||
email += 'a';
|
||||
} while (email.length < 256);
|
||||
|
||||
$('[type=email]').val(email);
|
||||
$('[type=password]').val('password');
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
||||
assert.isTrue(view.isValid());
|
||||
});
|
||||
|
||||
it('returns false if password is empty', function () {
|
||||
$('[type=email]').val(email);
|
||||
$('#fxa-age-year').val('1960');
|
||||
|
|
Загрузка…
Ссылка в новой задаче