mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-22 18:31:57 +03:00
d246a4761e
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
93 lines
3.4 KiB
JavaScript
93 lines
3.4 KiB
JavaScript
const debug = require('ghost-ignition').debug('web:parent');
|
|
const express = require('express');
|
|
const vhost = require('@tryghost/vhost-middleware');
|
|
const config = require('../config');
|
|
const compress = require('compression');
|
|
const netjet = require('netjet');
|
|
const shared = require('./shared');
|
|
const escapeRegExp = require('lodash.escaperegexp');
|
|
const {URL} = require('url');
|
|
const urlUtils = require('../lib/url-utils');
|
|
const storage = require('../adapters/storage');
|
|
const sentry = require('../sentry');
|
|
|
|
const STATIC_IMAGE_URL_PREFIX = `/${urlUtils.STATIC_IMAGE_URL_PREFIX}`;
|
|
|
|
module.exports = function setupParentApp(options = {}) {
|
|
debug('ParentApp setup start');
|
|
const parentApp = express();
|
|
parentApp.use(sentry.requestHandler);
|
|
|
|
// ## Global settings
|
|
|
|
// Make sure 'req.secure' is valid for proxied requests
|
|
// (X-Forwarded-Proto header will be checked, if present)
|
|
parentApp.enable('trust proxy');
|
|
|
|
parentApp.use(shared.middlewares.requestId);
|
|
parentApp.use(shared.middlewares.logRequest);
|
|
|
|
// Register event emmiter on req/res to trigger cache invalidation webhook event
|
|
parentApp.use(shared.middlewares.emitEvents);
|
|
|
|
// enabled gzip compression by default
|
|
if (config.get('compress') !== false) {
|
|
parentApp.use(compress());
|
|
}
|
|
|
|
// Preload link headers
|
|
if (config.get('preloadHeaders')) {
|
|
parentApp.use(netjet({
|
|
cache: {
|
|
max: config.get('preloadHeaders')
|
|
}
|
|
}));
|
|
}
|
|
|
|
// This sets global res.locals which are needed everywhere
|
|
parentApp.use(shared.middlewares.ghostLocals);
|
|
|
|
// Mount the apps on the parentApp
|
|
|
|
const adminHost = config.get('admin:url') ? (new URL(config.get('admin:url')).hostname) : '';
|
|
const frontendHost = new URL(config.get('url')).hostname;
|
|
const hasSeparateAdmin = adminHost && adminHost !== frontendHost;
|
|
|
|
// Wrap the admin and API apps into a single express app for use with vhost
|
|
const adminApp = express();
|
|
adminApp.use(sentry.requestHandler);
|
|
adminApp.enable('trust proxy'); // required to respect x-forwarded-proto in admin requests
|
|
adminApp.use('/ghost/api', require('./api')());
|
|
adminApp.use('/ghost/.well-known', require('./well-known')());
|
|
adminApp.use('/ghost', require('./admin')());
|
|
|
|
// TODO: remove {admin url}/content/* once we're sure the API is not returning relative asset URLs anywhere
|
|
// only register this route if the admin is separate so we're not overriding the {site}/content/* route
|
|
if (hasSeparateAdmin) {
|
|
adminApp.use(
|
|
STATIC_IMAGE_URL_PREFIX,
|
|
[
|
|
shared.middlewares.image.handleImageSizes,
|
|
storage.getStorage().serve(),
|
|
shared.middlewares.errorHandler.handleThemeResponse
|
|
]
|
|
);
|
|
}
|
|
|
|
// ADMIN + API
|
|
// with a separate admin url only serve on that host, otherwise serve on all hosts
|
|
const adminVhostArg = hasSeparateAdmin && adminHost ? adminHost : /.*/;
|
|
parentApp.use(vhost(adminVhostArg, adminApp));
|
|
|
|
// BLOG
|
|
// with a separate admin url we adjust the frontend vhost to exclude requests to that host, otherwise serve on all hosts
|
|
const frontendVhostArg = (hasSeparateAdmin && adminHost) ?
|
|
new RegExp(`^(?!${escapeRegExp(adminHost)}).*`) : /.*/;
|
|
|
|
parentApp.use(vhost(frontendVhostArg, require('./site')(options)));
|
|
|
|
debug('ParentApp setup end');
|
|
|
|
return parentApp;
|
|
};
|