0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-03 23:00:14 -05:00
ghost/test/regression/api/admin/authentication.test.js
Thibaut Patel daeb06e835 Added a theme parameter to the /authentication/setup route
refs https://github.com/TryGhost/Team/issues/1296

- The `theme` must be a github `org/repo` string
- This uses the internal API instead of the services because the API has extra implementation details not present in the services.
2022-02-07 12:03:40 +01:00

434 lines
15 KiB
JavaScript

const {expect} = require('chai');
const {any} = require('expect');
const security = require('@tryghost/security');
const testUtils = require('../../../utils');
const framework = require('../../../utils/e2e-framework');
const models = require('../../../../core/server/models');
const settingsCache = require('../../../../core/shared/settings-cache');
// Requires needed to enable a labs flag
const sinon = require('sinon');
const configUtils = require('../../../utils/configUtils');
describe('Authentication API canary', function () {
let agent;
let emailStub;
describe('Blog setup', function () {
before(async function () {
agent = await framework.getAgent('/ghost/api/canary/admin/');
});
after(async function () {
await framework.resetDb();
});
beforeEach(function () {
emailStub = framework.stubMail();
});
afterEach(function () {
framework.restoreMocks();
});
it('is setup? no', async function () {
const res = await agent
.get('authentication/setup')
.expectStatus(200);
expect(res.body).to.matchSnapshot();
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('complete setup', async function () {
// Enable the improvedOnboarding flag
configUtils.set('enableDeveloperExperiments', true);
sinon.stub(settingsCache, 'get');
settingsCache.get.withArgs('labs').returns({
improvedOnboarding: true
});
settingsCache.get.callThrough();
const res = await agent
.post('authentication/setup')
.body({
setup: [{
name: 'test user',
email: 'test@example.com',
password: 'thisissupersafe',
blogTitle: 'a test blog',
theme: 'TryGhost/Dawn'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(201);
expect(res.body).to.matchSnapshot({
users: [{
created_at: any(Date),
updated_at: any(Date)
}]
});
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
expect(emailStub.called).to.be.true;
expect(await settingsCache.get('active_theme')).to.eq('dawn');
});
it('is setup? yes', async function () {
const res = await agent
.get('authentication/setup');
expect(res.body).to.matchSnapshot();
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('complete setup again', function () {
return agent
.post('authentication/setup')
.body({
setup: [{
name: 'test user',
email: 'test-leo@example.com',
password: 'thisissupersafe',
blogTitle: 'a test blog'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(403);
});
it('update setup', async function () {
await framework.initFixtures();
await agent.loginAsOwner();
const res = await agent
.put('authentication/setup')
.body({
setup: [{
name: 'test user edit',
email: 'test-edit@example.com',
password: 'thisissupersafe',
blogTitle: 'a test blog'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(200);
expect(res.body).to.matchSnapshot({
users: [{
created_at: any(String),
last_seen: any(String),
updated_at: any(String)
}]
});
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
});
describe('Invitation', function () {
before(async function () {
agent = await framework.getAgent('/ghost/api/canary/admin/');
// NOTE: this order of fixture initialization boggles me. Ideally should not depend on agent/login sequence
await framework.initFixtures('invites');
await agent.loginAsOwner();
});
after(async function () {
await framework.resetDb();
});
it('check invite with invalid email', function () {
return agent
.get('authentication/invitation?email=invalidemail')
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(400);
});
it('check valid invite', async function () {
const res = await agent
.get(`authentication/invitation?email=${testUtils.DataGenerator.forKnex.invites[0].email}`)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(200);
expect(res.body).to.matchSnapshot();
});
it('check invalid invite', async function () {
const res = await agent
.get(`authentication/invitation?email=notinvited@example.org`)
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(200);
expect(res.body).to.matchSnapshot();
});
it('try to accept without invite', function () {
return agent
.post('authentication/invitation')
.body({
invitation: [{
token: 'lul11111',
password: 'lel123456',
email: 'not-invited@example.org',
name: 'not invited'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(404);
});
it('try to accept with invite and existing email address', function () {
return agent
.post('authentication/invitation')
.body({
invitation: [{
token: testUtils.DataGenerator.forKnex.invites[0].token,
password: '12345678910',
email: testUtils.DataGenerator.forKnex.users[0].email,
name: 'invited'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(422);
});
it('try to accept with invite', async function () {
const res = await agent
.post('authentication/invitation')
.body({
invitation: [{
token: testUtils.DataGenerator.forKnex.invites[0].token,
password: '12345678910',
email: testUtils.DataGenerator.forKnex.invites[0].email,
name: 'invited'
}]
})
.expectHeader('Content-Type', 'application/json; charset=utf-8')
.expectStatus(200);
expect(res.body).to.matchSnapshot();
});
});
describe('Password reset', function () {
const user = testUtils.DataGenerator.forModel.users[0];
before(async function () {
agent = await framework.getAgent('/ghost/api/canary/admin/');
// NOTE: this order of fixture initialization boggles me. Ideally should not depend on agent/login sequence
await framework.initFixtures('invites');
await agent.loginAsOwner();
});
after(async function () {
await framework.resetDb();
});
beforeEach(function () {
emailStub = framework.stubMail();
});
afterEach(function () {
framework.restoreMocks();
});
it('reset password', async function () {
const ownerUser = await models.User.getOwnerUser(testUtils.context.internal);
const token = security.tokens.resetToken.generateHash({
expires: Date.now() + (1000 * 60),
email: user.email,
dbHash: settingsCache.get('db_hash'),
password: ownerUser.get('password')
});
const res = await agent.put('authentication/passwordreset')
.header('Accept', 'application/json')
.body({
passwordreset: [{
token: token,
newPassword: 'thisissupersafe',
ne2Password: 'thisissupersafe'
}]
})
.expectStatus(200);
expect(res.body).to.matchSnapshot();
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('reset password: invalid token', async function () {
const res = await agent
.put('authentication/passwordreset')
.header('Accept', 'application/json')
.body({
passwordreset: [{
token: 'invalid',
newPassword: 'thisissupersafe',
ne2Password: 'thisissupersafe'
}]
})
.expectStatus(401);
expect(res.body).to.matchSnapshot({
errors: [{
id: any(String)
}]
});
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('reset password: expired token', async function () {
const ownerUser = await models.User.getOwnerUser(testUtils.context.internal);
const dateInThePast = Date.now() - (1000 * 60);
const token = security.tokens.resetToken.generateHash({
expires: dateInThePast,
email: user.email,
dbHash: settingsCache.get('db_hash'),
password: ownerUser.get('password')
});
const res = await agent
.put('authentication/passwordreset')
.header('Accept', 'application/json')
.body({
passwordreset: [{
token: token,
newPassword: 'thisissupersafe',
ne2Password: 'thisissupersafe'
}]
})
.expectStatus(400);
expect(res.body).to.matchSnapshot({
errors: [{
id: any(String)
}]
});
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('reset password: unmatched token', async function () {
const token = security.tokens.resetToken.generateHash({
expires: Date.now() + (1000 * 60),
email: user.email,
dbHash: settingsCache.get('db_hash'),
password: 'invalid_password'
});
const res = await agent
.put('authentication/passwordreset')
.header('Accept', 'application/json')
.body({
passwordreset: [{
token: token,
newPassword: 'thisissupersafe',
ne2Password: 'thisissupersafe'
}]
})
.expectStatus(400);
expect(res.body).to.matchSnapshot({
errors: [{
id: any(String)
}]
});
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
it('reset password: generate reset token', async function () {
const res = await agent
.post('authentication/passwordreset')
.header('Accept', 'application/json')
.body({
passwordreset: [{
email: user.email
}]
})
.expectStatus(200);
expect(res.body).to.matchSnapshot();
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
});
});
describe('Reset all passwords', function () {
let sendEmail;
before(async function () {
agent = await framework.getAgent('/ghost/api/canary/admin/');
// NOTE: this order of fixture initialization boggles me. Ideally should not depend on agent/login sequence
await framework.initFixtures('invites');
await agent.loginAsOwner();
});
after(async function () {
await framework.resetDb();
});
beforeEach(function () {
emailStub = framework.stubMail();
});
afterEach(function () {
framework.restoreMocks();
});
it('reset all passwords returns 200', async function () {
const res = await agent.post('authentication/reset_all_passwords')
.header('Accept', 'application/json')
.body({})
.expectStatus(200);
expect(res.body).to.matchSnapshot();
expect(res.headers).to.matchSnapshot({
date: any(String),
etag: any(String)
});
// All users locked
const users = await models.User.fetchAll();
for (const user of users) {
expect(user.get('status')).to.equal('locked');
}
// No session left
const sessions = await models.Session.fetchAll();
expect(sessions.length).to.equal(0);
expect(emailStub.callCount).to.equal(2);
expect(emailStub.firstCall.args[0].subject).to.equal('Reset Password');
expect(emailStub.secondCall.args[0].subject).to.equal('Reset Password');
});
});
});