const should = require('should'); const sinon = require('sinon'); const supertest = require('supertest'); const localUtils = require('./utils'); const testUtils = require('../../../../utils/index'); const models = require('../../../../../core/server/models/index'); const security = require('@tryghost/security'); const settingsCache = require('../../../../../core/shared/settings-cache'); const config = require('../../../../../core/shared/config/index'); const mailService = require('../../../../../core/server/services/mail/index'); const configUtils = require('../../../../utils/configUtils'); let ghost = testUtils.startGhost; let request; describe('Authentication API v2', function () { let ghostServer; describe('Blog setup: default config', function () { before(function () { return ghost({forceStart: true}) .then(function (_ghostServer) { ghostServer = _ghostServer; request = supertest.agent(config.get('url')); }); }); beforeEach(function () { sinon.stub(mailService.GhostMailer.prototype, 'send').resolves('Mail is disabled'); }); afterEach(function () { sinon.restore(); }); it('is setup? no', function () { return request .get(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.setup[0].status.should.be.false(); }); }); it('complete setup', function () { return request .post(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user', email: 'test@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(201) .then((res) => { const jsonResponse = res.body; should.exist(jsonResponse.users); should.not.exist(jsonResponse.meta); jsonResponse.users.should.have.length(1); localUtils.API.checkResponse(jsonResponse.users[0], 'user'); const newUser = jsonResponse.users[0]; newUser.id.should.equal(testUtils.DataGenerator.Content.users[0].id); newUser.name.should.equal('test user'); newUser.email.should.equal('test@example.com'); mailService.GhostMailer.prototype.send.called.should.be.true(); mailService.GhostMailer.prototype.send.args[0][0].to.should.equal('test@example.com'); }); }); it('is setup? yes', function () { return request .get(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.setup[0].status.should.be.true(); }); }); it('complete setup again', function () { return request .post(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user', email: 'test-leo@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(403); }); it('update setup', function () { return localUtils.doAuth(request) .then(() => { return request .put(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user edit', email: 'test-edit@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(200); }) .then((res) => { const jsonResponse = res.body; should.exist(jsonResponse.users); should.not.exist(jsonResponse.meta); jsonResponse.users.should.have.length(1); localUtils.API.checkResponse(jsonResponse.users[0], 'user'); const newUser = jsonResponse.users[0]; newUser.id.should.equal(testUtils.DataGenerator.Content.users[0].id); newUser.name.should.equal('test user edit'); newUser.email.should.equal('test-edit@example.com'); }); }); }); describe('Blog setup: custom config', function () { before(function () { return ghost({forceStart: true}) .then(function (_ghostServer) { ghostServer = _ghostServer; request = supertest.agent(config.get('url')); }); }); beforeEach(function () { configUtils.set({ sendWelcomeEmail: false // Default value is false in pro }); sinon.stub(mailService.GhostMailer.prototype, 'send').resolves('Mail is disabled'); }); afterEach(function () { configUtils.restore(); sinon.restore(); }); it('is setup? no', function () { return request .get(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.setup[0].status.should.be.false(); }); }); it('complete setup', function () { return request .post(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user', email: 'test@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(201) .then((res) => { const jsonResponse = res.body; should.exist(jsonResponse.users); should.not.exist(jsonResponse.meta); jsonResponse.users.should.have.length(1); localUtils.API.checkResponse(jsonResponse.users[0], 'user'); const newUser = jsonResponse.users[0]; newUser.id.should.equal(testUtils.DataGenerator.Content.users[0].id); newUser.name.should.equal('test user'); newUser.email.should.equal('test@example.com'); mailService.GhostMailer.prototype.send.called.should.be.false(); }); }); it('is setup? yes', function () { return request .get(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.setup[0].status.should.be.true(); }); }); it('complete setup again', function () { return request .post(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user', email: 'test-leo@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(403); }); it('update setup', function () { return localUtils.doAuth(request) .then(() => { return request .put(localUtils.API.getApiQuery('authentication/setup')) .set('Origin', config.get('url')) .send({ setup: [{ name: 'test user edit', email: 'test-edit@example.com', password: 'thisissupersafe', blogTitle: 'a test blog' }] }) .expect('Content-Type', /json/) .expect(200); }) .then((res) => { const jsonResponse = res.body; should.exist(jsonResponse.users); should.not.exist(jsonResponse.meta); jsonResponse.users.should.have.length(1); localUtils.API.checkResponse(jsonResponse.users[0], 'user'); const newUser = jsonResponse.users[0]; newUser.id.should.equal(testUtils.DataGenerator.Content.users[0].id); newUser.name.should.equal('test user edit'); newUser.email.should.equal('test-edit@example.com'); }); }); }); describe('Invitation', function () { before(function () { return ghost() .then(function (_ghostServer) { ghostServer = _ghostServer; request = supertest.agent(config.get('url')); // simulates blog setup (initialises the owner) return localUtils.doAuth(request, 'invites'); }); }); it('check invite with invalid email', function () { return request .get(localUtils.API.getApiQuery('authentication/invitation?email=invalidemail')) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(400); }); it('check valid invite', function () { return request .get(localUtils.API.getApiQuery(`authentication/invitation?email=${testUtils.DataGenerator.forKnex.invites[0].email}`)) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.invitation[0].valid.should.equal(true); }); }); it('check invalid invite', function () { return request .get(localUtils.API.getApiQuery(`authentication/invitation?email=notinvited@example.org`)) .set('Origin', config.get('url')) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.invitation[0].valid.should.equal(false); }); }); it('try to accept without invite', function () { return request .post(localUtils.API.getApiQuery('authentication/invitation')) .set('Origin', config.get('url')) .send({ invitation: [{ token: 'lul11111', password: 'lel123456', email: 'not-invited@example.org', name: 'not invited' }] }) .expect('Content-Type', /json/) .expect(404); }); it('try to accept with invite', function () { return request .post(localUtils.API.getApiQuery('authentication/invitation')) .set('Origin', config.get('url')) .send({ invitation: [{ token: testUtils.DataGenerator.forKnex.invites[0].token, password: '12345678910', email: testUtils.DataGenerator.forKnex.invites[0].email, name: 'invited' }] }) .expect('Content-Type', /json/) .expect(200) .then((res) => { res.body.invitation[0].message.should.equal('Invitation accepted.'); }); }); }); 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) { const 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) .then((res) => { should.exist(res.body.errors); res.body.errors[0].type.should.eql('UnauthorizedError'); res.body.errors[0].message.should.eql('Cannot reset password.'); }); }); 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); }); }); }); });