mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
no-issue This adds two new endpoints, one at /ghost/.well-known/jwks.json for exposing a public key, and one on the canary api /identities, which allows the Owner user to fetch a JWT. This token can then be used by external services to verify the domain * Added ghost_{public,private}_key settings This key can be used for generating tokens for communicating with external services on behalf of Ghost * Added .well-known directory to /ghost/.well-known We add a jwks.json file to the .well-known directory which exposes a public JWK which can be used to verify the signatures of JWT's created by Ghost This is added to the /ghost/ path so that it can live on the admin domain, rather than the frontend. This is because most of its uses/functions will be in relation to the admin domain. * Improved settings model tests This removes hardcoded positions in favour of testing that a particular event wasn't emitted which is less brittle and more precise about what's being tested * Fixed parent app unit tests for well-known This updates the parent app unit tests to check that the well-known route is mounted. We all change proxyquire to use `noCallThru` which ensures that the ubderlying modules are not required. This stops the initialisation logic in ./well-known erroring in tests https://github.com/thlorenz/proxyquire/issues/215 * Moved jwt signature to a separate 'token' propery This structure corresponds to other resources and allows to exptend with additional properties in future if needed
172 lines
5.8 KiB
JavaScript
172 lines
5.8 KiB
JavaScript
const should = require('should');
|
|
const sinon = require('sinon');
|
|
const mockDb = require('mock-knex');
|
|
const models = require('../../../server/models');
|
|
const {knex} = require('../../../server/data/db');
|
|
const common = require('../../../server/lib/common');
|
|
|
|
describe('Unit: models/settings', function () {
|
|
before(function () {
|
|
models.init();
|
|
});
|
|
|
|
describe('events', function () {
|
|
let tracker;
|
|
let eventSpy;
|
|
|
|
beforeEach(function () {
|
|
mockDb.mock(knex);
|
|
tracker = mockDb.getTracker();
|
|
tracker.install();
|
|
});
|
|
|
|
afterEach(function () {
|
|
mockDb.unmock(knex);
|
|
});
|
|
|
|
beforeEach(function () {
|
|
eventSpy = sinon.spy(common.events, 'emit');
|
|
});
|
|
|
|
afterEach(function () {
|
|
sinon.restore();
|
|
});
|
|
|
|
it('emits add events', function () {
|
|
tracker.on('query', (query, step) => {
|
|
return [
|
|
function fetchAddQuery() {
|
|
query.response([{}]);
|
|
},
|
|
function addQuery() {
|
|
query.response([{
|
|
key: 'description',
|
|
value: 'added value'
|
|
}]);
|
|
}
|
|
][step - 1]();
|
|
});
|
|
|
|
return models.Settings.edit({
|
|
key: 'description',
|
|
value: 'added value'
|
|
})
|
|
.then(() => {
|
|
eventSpy.calledTwice.should.be.true();
|
|
eventSpy.firstCall.calledWith('settings.added').should.be.true();
|
|
eventSpy.secondCall.calledWith('settings.description.added').should.be.true();
|
|
});
|
|
});
|
|
|
|
it('emits edit events', function () {
|
|
tracker.on('query', (query, step) => {
|
|
return [
|
|
function fetchEditQuery() {
|
|
query.response([{
|
|
id: 1, // NOTE: `id` imitates existing value for 'edit' event
|
|
key: 'description',
|
|
value: 'db value'
|
|
}]);
|
|
}
|
|
][step - 1]();
|
|
});
|
|
|
|
return models.Settings.edit({
|
|
key: 'description',
|
|
value: 'edited value'
|
|
})
|
|
.then(() => {
|
|
eventSpy.calledTwice.should.be.true();
|
|
eventSpy.firstCall.calledWith('settings.edited').should.be.true();
|
|
eventSpy.secondCall.calledWith('settings.description.edited').should.be.true();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('defaults', function () {
|
|
let tracker;
|
|
let eventSpy;
|
|
|
|
beforeEach(function () {
|
|
mockDb.mock(knex);
|
|
tracker = mockDb.getTracker();
|
|
tracker.install();
|
|
});
|
|
|
|
afterEach(function () {
|
|
mockDb.unmock(knex);
|
|
tracker.uninstall();
|
|
});
|
|
|
|
beforeEach(function () {
|
|
eventSpy = sinon.spy(common.events, 'emit');
|
|
});
|
|
|
|
afterEach(function () {
|
|
sinon.restore();
|
|
});
|
|
|
|
it('populates unset defaults', function () {
|
|
tracker.on('query', (query) => {
|
|
return query.response([{}]);
|
|
});
|
|
|
|
return models.Settings.populateDefaults()
|
|
.then(() => {
|
|
// 2 events per item - settings.added and settings.[name].added
|
|
eventSpy.callCount.should.equal(92);
|
|
const eventsEmitted = eventSpy.args.map(args => args[0]);
|
|
const checkEventEmitted = event => should.ok(eventsEmitted.includes(event), `${event} event should be emitted`);
|
|
|
|
checkEventEmitted('settings.db_hash.added');
|
|
checkEventEmitted('settings.description.added');
|
|
|
|
checkEventEmitted('settings.default_content_visibility.added');
|
|
checkEventEmitted('settings.members_subscription_settings.added');
|
|
});
|
|
});
|
|
|
|
it('doesn\'t overwrite any existing settings', function () {
|
|
tracker.on('query', (query) => {
|
|
return query.response([{
|
|
key: 'description',
|
|
value: 'Adam\'s Blog'
|
|
}]);
|
|
});
|
|
|
|
return models.Settings.populateDefaults()
|
|
.then(() => {
|
|
const eventsEmitted = eventSpy.args.map(args => args[0]);
|
|
const checkEventNotEmitted = event => should.ok(!eventsEmitted.includes(event), `${event} event should be emitted`);
|
|
checkEventNotEmitted('settings.description.added');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('parse', function () {
|
|
it('ensure correct parsing when fetching from db', function () {
|
|
const setting = models.Settings.forge();
|
|
|
|
let returns = setting.parse({key: 'is_private', value: 'false'});
|
|
should.equal(returns.value, false);
|
|
|
|
returns = setting.parse({key: 'is_private', value: false});
|
|
should.equal(returns.value, false);
|
|
|
|
returns = setting.parse({key: 'is_private', value: true});
|
|
should.equal(returns.value, true);
|
|
|
|
returns = setting.parse({key: 'is_private', value: 'true'});
|
|
should.equal(returns.value, true);
|
|
|
|
returns = setting.parse({key: 'is_private', value: '0'});
|
|
should.equal(returns.value, false);
|
|
|
|
returns = setting.parse({key: 'is_private', value: '1'});
|
|
should.equal(returns.value, true);
|
|
|
|
returns = setting.parse({key: 'something', value: 'null'});
|
|
should.equal(returns.value, 'null');
|
|
});
|
|
});
|
|
});
|