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) {
|
isElementValid: function (selector) {
|
||||||
var el = this.$(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 value = el.val();
|
||||||
var isValid = !!(value && el[0].validity.valid);
|
var isValid = !!(value && el[0].validity.valid);
|
||||||
return isValid;
|
return isValid;
|
||||||
|
@ -183,6 +190,38 @@ function (_, $, BaseView, Tooltip) {
|
||||||
showValidationErrorsEnd: function () {
|
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) {
|
showEmailValidationError: function (which) {
|
||||||
this.showValidationError(which, t('Valid email required'));
|
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 () {
|
it('returns false if email is empty', function () {
|
||||||
|
$('[type=email]').val('');
|
||||||
$('[type=password]').val('password');
|
$('[type=password]').val('password');
|
||||||
$('#fxa-age-year').val('1960');
|
$('#fxa-age-year').val('1960');
|
||||||
|
|
||||||
|
@ -76,6 +77,131 @@ function (chai, _, $, View, Session, FxaClient, RouterMock) {
|
||||||
assert.isFalse(view.isValid());
|
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 () {
|
it('returns false if password is empty', function () {
|
||||||
$('[type=email]').val(email);
|
$('[type=email]').val(email);
|
||||||
$('#fxa-age-year').val('1960');
|
$('#fxa-age-year').val('1960');
|
||||||
|
|
Загрузка…
Ссылка в новой задаче