mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Expanded authentication test suite with cases for password reset flow
- Added missing endpoint coverage - Minor fixes with formatting and validations uncovered by the test - Added same test to v0.1 coverage
This commit is contained in:
parent
3945e8a5ee
commit
956da204f2
5 changed files with 161 additions and 4 deletions
|
@ -91,6 +91,9 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
generateResetToken: {
|
generateResetToken: {
|
||||||
|
validation: {
|
||||||
|
docName: 'passwordreset'
|
||||||
|
},
|
||||||
permissions: true,
|
permissions: true,
|
||||||
options: [
|
options: [
|
||||||
'email'
|
'email'
|
||||||
|
@ -101,7 +104,7 @@ module.exports = {
|
||||||
return auth.setup.assertSetupCompleted(true)();
|
return auth.setup.assertSetupCompleted(true)();
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return auth.passwordreset.generateToken(frame.data.email, api.settings);
|
return auth.passwordreset.generateToken(frame.data.passwordreset[0].email, api.settings);
|
||||||
})
|
})
|
||||||
.then((token) => {
|
.then((token) => {
|
||||||
return auth.passwordreset.sendResetNotification(token, api.mail);
|
return auth.passwordreset.sendResetNotification(token, api.mail);
|
||||||
|
@ -113,7 +116,6 @@ module.exports = {
|
||||||
validation: {
|
validation: {
|
||||||
docName: 'passwordreset',
|
docName: 'passwordreset',
|
||||||
data: {
|
data: {
|
||||||
token: {required: true},
|
|
||||||
newPassword: {required: true},
|
newPassword: {required: true},
|
||||||
ne2Password: {required: true}
|
ne2Password: {required: true}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,22 @@ module.exports = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
generateResetToken(data, apiConfig, frame) {
|
||||||
|
frame.response = {
|
||||||
|
passwordreset: [{
|
||||||
|
message: common.i18n.t('common.api.authentication.mail.checkEmailForInstructions')
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
resetPassword(data, apiConfig, frame) {
|
||||||
|
frame.response = {
|
||||||
|
passwordreset: [{
|
||||||
|
message: common.i18n.t('common.api.authentication.mail.passwordChanged')
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
acceptInvitation(data, apiConfig, frame) {
|
acceptInvitation(data, apiConfig, frame) {
|
||||||
debug('acceptInvitation');
|
debug('acceptInvitation');
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
|
const validator = require('validator');
|
||||||
const debug = require('ghost-ignition').debug('api:v2:utils:validators:input:passwordreset');
|
const debug = require('ghost-ignition').debug('api:v2:utils:validators:input:passwordreset');
|
||||||
const common = require('../../../../../lib/common');
|
const common = require('../../../../../lib/common');
|
||||||
|
|
||||||
|
@ -13,5 +14,17 @@ module.exports = {
|
||||||
message: common.i18n.t('errors.models.user.newPasswordsDoNotMatch')
|
message: common.i18n.t('errors.models.user.newPasswordsDoNotMatch')
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
generateResetToken(apiConfig, frame) {
|
||||||
|
debug('generateResetToken');
|
||||||
|
|
||||||
|
const email = frame.data.passwordreset[0].email;
|
||||||
|
|
||||||
|
if (typeof email !== 'string' || !validator.isEmail(email)) {
|
||||||
|
throw new common.errors.BadRequestError({
|
||||||
|
message: common.i18n.t('errors.api.authentication.invalidEmailReceived')
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,12 @@ describe('Authentication API', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
sinon.stub(mailService.GhostMailer.prototype, 'send').resolves('Mail is disabled');
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
|
sinon.restore();
|
||||||
return testUtils.clearBruteData();
|
return testUtils.clearBruteData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -271,6 +276,27 @@ describe('Authentication API', function () {
|
||||||
.expect(401);
|
.expect(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reset password: send reset password', function () {
|
||||||
|
return request
|
||||||
|
.post(localUtils.API.getApiQuery('authentication/passwordreset/'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.send({
|
||||||
|
passwordreset: [{
|
||||||
|
email: user.email
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => {
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.passwordreset[0].message);
|
||||||
|
jsonResponse.passwordreset[0].message.should.equal('Check your email for further instructions.');
|
||||||
|
mailService.GhostMailer.prototype.send.args[0][0].to.should.equal(user.email);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('revoke token', function () {
|
it('revoke token', function () {
|
||||||
return request
|
return request
|
||||||
.post(localUtils.API.getApiQuery('authentication/revoke'))
|
.post(localUtils.API.getApiQuery('authentication/revoke'))
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
const should = require('should');
|
const should = require('should');
|
||||||
const sinon = require('sinon');
|
const sinon = require('sinon');
|
||||||
const supertest = require('supertest');
|
const supertest = require('supertest');
|
||||||
const testUtils = require('../../../../utils/index');
|
|
||||||
const localUtils = require('./utils');
|
const localUtils = require('./utils');
|
||||||
|
const testUtils = require('../../../../utils/index');
|
||||||
|
const models = require('../../../../../server/models/index');
|
||||||
|
const security = require('../../../../../server/lib/security/index');
|
||||||
|
const settingsCache = require('../../../../../server/services/settings/cache');
|
||||||
const config = require('../../../../../server/config/index');
|
const config = require('../../../../../server/config/index');
|
||||||
const mailService = require('../../../../../server/services/mail/index');
|
const mailService = require('../../../../../server/services/mail/index');
|
||||||
|
|
||||||
let ghost = testUtils.startGhost;
|
let ghost = testUtils.startGhost;
|
||||||
let request;
|
let request;
|
||||||
|
|
||||||
describe.only('Authentication API v2', function () {
|
describe('Authentication API v2', function () {
|
||||||
let ghostServer;
|
let ghostServer;
|
||||||
|
|
||||||
describe('Blog setup', function () {
|
describe('Blog setup', function () {
|
||||||
|
@ -209,4 +212,101 @@ describe.only('Authentication API v2', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Password reset', function () {
|
||||||
|
const user = testUtils.DataGenerator.forModel.users[0];
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(() => {
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return localUtils.doAuth(request);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
sinon.stub(mailService.GhostMailer.prototype, 'send').resolves('Mail is disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reset password', function (done) {
|
||||||
|
models.User.getOwnerUser(testUtils.context.internal)
|
||||||
|
.then(function (ownerUser) {
|
||||||
|
var token = security.tokens.resetToken.generateHash({
|
||||||
|
expires: Date.now() + (1000 * 60),
|
||||||
|
email: user.email,
|
||||||
|
dbHash: settingsCache.get('db_hash'),
|
||||||
|
password: ownerUser.get('password')
|
||||||
|
});
|
||||||
|
|
||||||
|
request.put(localUtils.API.getApiQuery('authentication/passwordreset'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.send({
|
||||||
|
passwordreset: [{
|
||||||
|
token: token,
|
||||||
|
newPassword: 'thisissupersafe',
|
||||||
|
ne2Password: 'thisissupersafe'
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.passwordreset[0].message);
|
||||||
|
jsonResponse.passwordreset[0].message.should.equal('Password changed successfully.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reset password: invalid token', function () {
|
||||||
|
return request
|
||||||
|
.put(localUtils.API.getApiQuery('authentication/passwordreset'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.send({
|
||||||
|
passwordreset: [{
|
||||||
|
token: 'invalid',
|
||||||
|
newPassword: 'thisissupersafe',
|
||||||
|
ne2Password: 'thisissupersafe'
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reset password: generate reset token', function () {
|
||||||
|
return request
|
||||||
|
.post(localUtils.API.getApiQuery('authentication/passwordreset'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.send({
|
||||||
|
passwordreset: [{
|
||||||
|
email: user.email
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.then((res) => {
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.passwordreset[0].message);
|
||||||
|
jsonResponse.passwordreset[0].message.should.equal('Check your email for further instructions.');
|
||||||
|
mailService.GhostMailer.prototype.send.args[0][0].to.should.equal(user.email);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue