mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Merge pull request #1954 from ErisDS/issue-1498
Adding case-insensitive User.getByEmail method
This commit is contained in:
commit
c1290d77a6
@ -69,11 +69,10 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
// disabling sanitization until we can implement a better version
|
||||
// this.set('name', this.sanitize('name'));
|
||||
// this.set('email', this.sanitize('email').toLocaleLowerCase());
|
||||
// this.set('email', this.sanitize('email'));
|
||||
// this.set('location', this.sanitize('location'));
|
||||
// this.set('website', this.sanitize('website'));
|
||||
// this.set('bio', this.sanitize('bio'));
|
||||
this.set('email', this.get('email').toLocaleLowerCase());
|
||||
|
||||
return ghostBookshelf.Model.prototype.saving.apply(this, arguments);
|
||||
},
|
||||
@ -182,9 +181,8 @@ User = ghostBookshelf.Model.extend({
|
||||
check: function (_userdata) {
|
||||
var self = this,
|
||||
s;
|
||||
return this.forge({
|
||||
email: _userdata.email.toLocaleLowerCase()
|
||||
}).fetch({require: true}).then(function (user) {
|
||||
|
||||
return this.getByEmail(_userdata.email).then(function (user) {
|
||||
if (user.get('status') !== 'locked') {
|
||||
return nodefn.call(bcrypt.compare, _userdata.pw, user.get('password')).then(function (matched) {
|
||||
if (!matched) {
|
||||
@ -205,8 +203,11 @@ User = ghostBookshelf.Model.extend({
|
||||
'the "Forgotten password?" link!'));
|
||||
|
||||
}, function (error) {
|
||||
/*jslint unparam:true*/
|
||||
return when.reject(new Error('There is no user with that email address.'));
|
||||
if (error.message === 'NotFound' || error.message === 'EmptyResponse') {
|
||||
return when.reject(new Error('There is no user with that email address.'));
|
||||
}
|
||||
|
||||
return when.reject(error);
|
||||
});
|
||||
},
|
||||
|
||||
@ -248,7 +249,7 @@ User = ghostBookshelf.Model.extend({
|
||||
},
|
||||
|
||||
generateResetToken: function (email, expires, dbHash) {
|
||||
return this.forge({email: email.toLocaleLowerCase()}).fetch({require: true}).then(function (foundUser) {
|
||||
return this.getByEmail(email).then(function (foundUser) {
|
||||
var hash = crypto.createHash('sha256'),
|
||||
text = "";
|
||||
|
||||
@ -375,8 +376,28 @@ User = ghostBookshelf.Model.extend({
|
||||
});
|
||||
|
||||
return checkPromise.promise;
|
||||
}
|
||||
},
|
||||
|
||||
// Get the user by email address, enforces case insensitivity rejects if the user is not found
|
||||
// When multi-user support is added, email addresses must be deduplicated with case insensitivity, so that
|
||||
// joe@bloggs.com and JOE@BLOGGS.COM cannot be created as two separate users.
|
||||
getByEmail: function (email) {
|
||||
// We fetch all users and process them in JS as there is no easy way to make this query across all DBs
|
||||
// Although they all support `lower()`, sqlite can't case transform unicode characters
|
||||
// This is somewhat mute, as validator.isEmail() also doesn't support unicode, but this is much easier / more
|
||||
// likely to be fixed in the near future.
|
||||
return Users.forge().fetch({require: true}).then(function (users) {
|
||||
var userWithEmail = users.find(function (user) {
|
||||
return user.get('email').toLowerCase() === email.toLowerCase();
|
||||
});
|
||||
|
||||
if (userWithEmail) {
|
||||
return when.resolve(userWithEmail);
|
||||
}
|
||||
|
||||
return when.reject(new Error('NotFound'));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Users = ghostBookshelf.Collection.extend({
|
||||
|
@ -49,7 +49,7 @@ describe('User Model', function run() {
|
||||
}).then(null, done);
|
||||
});
|
||||
|
||||
it('can lowercase email', function (done) {
|
||||
it('does NOT lowercase email', function (done) {
|
||||
var userData = testUtils.DataGenerator.forModel.users[2],
|
||||
gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) {
|
||||
return when.resolve(userData);
|
||||
@ -58,7 +58,7 @@ describe('User Model', function run() {
|
||||
UserModel.add(userData).then(function (createdUser) {
|
||||
should.exist(createdUser);
|
||||
createdUser.has('uuid').should.equal(true);
|
||||
createdUser.attributes.email.should.eql(userData.email.toLocaleLowerCase(), "email address correct");
|
||||
createdUser.attributes.email.should.eql(userData.email, "email address correct");
|
||||
gravatarStub.restore();
|
||||
done();
|
||||
}).then(null, done);
|
||||
@ -80,7 +80,7 @@ describe('User Model', function run() {
|
||||
}).then(null, done);
|
||||
});
|
||||
|
||||
it('can handle no gravatar', function(done) {
|
||||
it('can handle no gravatar', function (done) {
|
||||
var userData = testUtils.DataGenerator.forModel.users[0],
|
||||
gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) {
|
||||
return when.resolve(userData);
|
||||
@ -94,6 +94,39 @@ describe('User Model', function run() {
|
||||
done();
|
||||
}).then(null, done);
|
||||
});
|
||||
|
||||
it('can find by email and is case insensitive', function (done) {
|
||||
var userData = testUtils.DataGenerator.forModel.users[2],
|
||||
email = testUtils.DataGenerator.forModel.users[2].email;
|
||||
|
||||
UserModel.add(userData).then(function () {
|
||||
// Test same case
|
||||
return UserModel.getByEmail(email).then(function (user) {
|
||||
should.exist(user);
|
||||
user.attributes.email.should.eql(email);
|
||||
});
|
||||
}).then(function () {
|
||||
// Test entered in lowercase
|
||||
return UserModel.getByEmail(email.toLowerCase()).then(function (user) {
|
||||
should.exist(user);
|
||||
user.attributes.email.should.eql(email);
|
||||
});
|
||||
}).then(function () {
|
||||
// Test entered in uppercase
|
||||
return UserModel.getByEmail(email.toUpperCase()).then(function (user) {
|
||||
should.exist(user);
|
||||
user.attributes.email.should.eql(email);
|
||||
});
|
||||
}).then(function () {
|
||||
// Test incorrect email address - swapped capital O for number 0
|
||||
return UserModel.getByEmail('jb0gendAth@example.com').then(null, function (error) {
|
||||
should.exist(error);
|
||||
error.message.should.eql('NotFound');
|
||||
});
|
||||
}).then(function () {
|
||||
done();
|
||||
}).then(null, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Basic Operations', function () {
|
||||
@ -252,7 +285,7 @@ describe('User Model', function run() {
|
||||
return UserModel.generateResetToken(results.models[0].attributes.email, expires, dbHash);
|
||||
|
||||
}).then(function (token) {
|
||||
|
||||
|
||||
return UserModel.validateToken(token, dbHash);
|
||||
|
||||
}).then(function () {
|
||||
@ -278,7 +311,7 @@ describe('User Model', function run() {
|
||||
return UserModel.generateResetToken(firstUser.attributes.email, expires, dbHash);
|
||||
|
||||
}).then(function (token) {
|
||||
|
||||
|
||||
return UserModel.resetPassword(token, 'newpassword', 'newpassword', dbHash);
|
||||
|
||||
}).then(function (resetUser) {
|
||||
@ -329,7 +362,7 @@ describe('User Model', function run() {
|
||||
return UserModel.generateResetToken(results.models[0].attributes.email, expires, dbHash);
|
||||
|
||||
}).then(function (token) {
|
||||
|
||||
|
||||
var tokenText = new Buffer(token, 'base64').toString('ascii'),
|
||||
parts = tokenText.split('|'),
|
||||
fakeExpires,
|
||||
@ -341,7 +374,7 @@ describe('User Model', function run() {
|
||||
fakeToken = new Buffer(fakeToken).toString('base64');
|
||||
|
||||
return UserModel.validateToken(fakeToken, dbHash);
|
||||
|
||||
|
||||
}).then(function () {
|
||||
throw new Error("allowed invalid token");
|
||||
}, function (err) {
|
||||
|
Loading…
Reference in New Issue
Block a user