More comprehensive validation of email addresses.
This commit is contained in:
Родитель
c75223cc4c
Коммит
7ef3dcbac3
|
@ -4,7 +4,6 @@
|
|||
|
||||
var validators = require('./validators')
|
||||
var HEX_STRING = validators.HEX_STRING
|
||||
var LAZY_EMAIL = validators.LAZY_EMAIL
|
||||
|
||||
var Password = require('../crypto/password')
|
||||
var butil = require('../crypto/butil')
|
||||
|
@ -30,7 +29,7 @@ module.exports = function (
|
|||
config: {
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
authPW: isA.string().min(64).max(64).regex(HEX_STRING).required(),
|
||||
preVerified: isA.boolean(),
|
||||
service: isA.string().max(16).alphanum().optional(),
|
||||
|
@ -164,7 +163,7 @@ module.exports = function (
|
|||
config: {
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
authPW: isA.string().min(64).max(64).regex(HEX_STRING).required()
|
||||
},
|
||||
},
|
||||
|
@ -326,7 +325,7 @@ module.exports = function (
|
|||
},
|
||||
response: {
|
||||
schema: {
|
||||
email: isA.string().regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
verified: isA.boolean().required()
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +452,7 @@ module.exports = function (
|
|||
config: {
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
authPW: isA.string().min(64).max(64).regex(HEX_STRING).required()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
var validators = require('./validators')
|
||||
var HEX_STRING = validators.HEX_STRING
|
||||
var LAZY_EMAIL = validators.LAZY_EMAIL
|
||||
|
||||
var crypto = require('crypto')
|
||||
var Password = require('../crypto/password')
|
||||
|
@ -33,7 +32,7 @@ module.exports = function (
|
|||
config: {
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
oldAuthPW: isA.string().min(64).max(64).regex(HEX_STRING).required()
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +161,7 @@ module.exports = function (
|
|||
config: {
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
service: isA.string().max(16).alphanum().optional(),
|
||||
redirectTo: isA.string()
|
||||
.max(512)
|
||||
|
@ -230,7 +229,7 @@ module.exports = function (
|
|||
},
|
||||
validate: {
|
||||
payload: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
service: isA.string().max(16).alphanum().optional(),
|
||||
redirectTo: isA.string()
|
||||
.max(512)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
var validators = require('./validators')
|
||||
var HEX_STRING = validators.HEX_STRING
|
||||
var LAZY_EMAIL = validators.LAZY_EMAIL
|
||||
|
||||
module.exports = function (log, crypto, isA, config, redirectDomain) {
|
||||
|
||||
|
@ -42,7 +41,7 @@ module.exports = function (log, crypto, isA, config, redirectDomain) {
|
|||
config: {
|
||||
validate: {
|
||||
query: {
|
||||
email: isA.string().max(255).regex(LAZY_EMAIL).required(),
|
||||
email: validators.email().required(),
|
||||
code: isA.string().max(32).regex(HEX_STRING).required(),
|
||||
token: isA.string().max(64).regex(HEX_STRING).required(),
|
||||
service: isA.string().max(16).alphanum().optional(),
|
||||
|
|
|
@ -2,11 +2,94 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var punycode = require('punycode')
|
||||
var isA = require('hapi').types
|
||||
|
||||
// Match any non-empty hex-encoded string.
|
||||
|
||||
module.exports.HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
module.exports.LAZY_EMAIL = /^[^@\s]+@[^@\s]+$/
|
||||
|
||||
// Joi validator to match any valid email address.
|
||||
// This is different to Joi's builtin email validator, and
|
||||
// requires a custom validation function.
|
||||
|
||||
module.exports.email = function() {
|
||||
var email = isA.string().max(255)
|
||||
// Imma add a custom test to this Joi object using internal
|
||||
// properties because I can't find a nice API to do that.
|
||||
email._tests.push({ func: function(value, state, options) {
|
||||
if (value !== undefined && value !== null) {
|
||||
if (module.exports.isValidEmailAddress(value)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'validators.email',
|
||||
context: { key: '<root>' },
|
||||
path: state.path
|
||||
}
|
||||
}})
|
||||
return email
|
||||
}
|
||||
|
||||
|
||||
// Function to validate an email address.
|
||||
// This is a transliteration of the HTML5 email-validation logic
|
||||
// inside Firefox. It splits the username and domain portions,
|
||||
// translates tham into IDN punycode syntax, then does some very
|
||||
// basic sanity-checking.
|
||||
|
||||
module.exports.isValidEmailAddress = function(value) {
|
||||
// It cant be empty or end with strange chars.
|
||||
if (!value) {
|
||||
return false
|
||||
}
|
||||
if (value[value.length - 1] === '.' || value[value.length - 1] === '-') {
|
||||
return false
|
||||
}
|
||||
// It must contain an '@' somewhere in the middle.
|
||||
var atPos = value.indexOf('@')
|
||||
if (atPos === -1 || atPos === 0 || atPos === value.length) {
|
||||
return false
|
||||
}
|
||||
var username = value.substring(0, atPos)
|
||||
var domain = value.substring(atPos + 1)
|
||||
// Unicode is hard, let's work with ascii only.
|
||||
username = punycode.toASCII(username)
|
||||
domain = punycode.toASCII(domain)
|
||||
// The username portion must contain only allowed characters.
|
||||
for (var i = 0; i < username.length; i++) {
|
||||
if (!username[i].match(/[a-zA-Z0-9.!#$%&'*+-\/=?^_`{|}~]/)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// The domain portion can't begin with a dot or a dash.
|
||||
if (domain[0] === '.' || domain[i] === '-') {
|
||||
return false
|
||||
}
|
||||
// The domain portion must be a valid punycode domain.
|
||||
for (i = 0; i < domain.length; i++) {
|
||||
if (domain[i] === '.') {
|
||||
// A dot can't follow a dot or a dash.
|
||||
if (domain[i - 1] === '.' || domain[i - 1] === '-') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
else if (domain[i] === '-') {
|
||||
// A dash can't follow a dot.
|
||||
if (domain[i - 1] === '.') {
|
||||
return false
|
||||
}
|
||||
} else if (!domain[i].match(/[a-zA-Z0-9-]/)) {
|
||||
// The domain characters must be alphanumeric.
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Match any subdomain of the given hostname.
|
||||
|
||||
module.exports.domainRegex = function (hostname) {
|
||||
if (!hostname) { return new RegExp() }
|
||||
|
|
|
@ -231,7 +231,7 @@ TestServer.start(config)
|
|||
}
|
||||
).then(
|
||||
function () {
|
||||
t.ok(client.sessionToken, "client can login")
|
||||
t.ok(client.sessionToken, 'client can login')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -280,15 +280,106 @@ TestServer.start(config)
|
|||
)
|
||||
|
||||
test(
|
||||
'/account/create with malformed email address',
|
||||
'/account/create with a variety of malformed email addresses',
|
||||
function (t) {
|
||||
var email = 'notAnEmailAddress'
|
||||
var password = '123456'
|
||||
return Client.create(config.publicUrl, email, password, server.mailbox)
|
||||
var pwd = '123456'
|
||||
return Client.create(config.publicUrl, 'notAnEmailAddress', pwd)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
return Client.create(config.publicUrl, '\n@example.com', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
return Client.create(config.publicUrl, 'me@hello world.com', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
return Client.create(config.publicUrl, 'me@hello+world.com', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
return Client.create(config.publicUrl, 'me@.example', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
return Client.create(config.publicUrl, 'me@example.com-', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'malformed email is rejected')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'/account/create with a variety of unusual but valid email addresses',
|
||||
function (t) {
|
||||
var pwd = '123456'
|
||||
return Client.create(config.publicUrl, 'a+b+c@example.com', pwd)
|
||||
.then(
|
||||
function (c) {
|
||||
return c.destroyAccount()
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 101, 'unusual email is not invalid')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return Client.create(config.publicUrl, '#!?-@t-e-s-t.c-o-m', pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (c) {
|
||||
return c.destroyAccount()
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 101, 'unusual email is not invalid')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
var email = String.fromCharCode(1234) + '@example.com'
|
||||
return Client.create(config.publicUrl, email, pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (c) {
|
||||
return c.destroyAccount()
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 101, 'unusual email is not invalid')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
var email = 'test@' + String.fromCharCode(5678) + '.com'
|
||||
return Client.create(config.publicUrl, email, pwd)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (c) {
|
||||
return c.destroyAccount()
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 101, 'unusual email is not invalid')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче