mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
* 💄 Combine slashes & uncapitalise middleware - these bits of middleware belong together - ideally they should be optimised * 🎨 Move ghostLocals out of themeHandler GhostLocals sets several important values which are needed for every part of the application, admin, api and theme. Therefore, it doesn't make sense for it to be bundled in the themeHandler. * 🐛 Fix the uncapitalise middleware - Updated to make correct use of req.baseUrl, req.path, req.url & req.originalUrl - Updated the tests to actually cover our weird cases * 🎨 Move ghostVersion logic out of config * 💄 Group static / asset-related middleware together * 🔥 Remove /shared/ asset handling - The 5 files which are located in `/shared/` are all handled by individual calls to `serveSharedFile` - Therefore this code is redundant
216 lines
7.1 KiB
JavaScript
216 lines
7.1 KiB
JavaScript
var debug = require('debug')('ghost:middleware'),
|
|
bodyParser = require('body-parser'),
|
|
compress = require('compression'),
|
|
express = require('express'),
|
|
hbs = require('express-hbs'),
|
|
path = require('path'),
|
|
netjet = require('netjet'),
|
|
multer = require('multer'),
|
|
tmpdir = require('os').tmpdir,
|
|
serveStatic = require('express').static,
|
|
routes = require('../routes'),
|
|
config = require('../config'),
|
|
storage = require('../storage'),
|
|
logging = require('../logging'),
|
|
errors = require('../errors'),
|
|
i18n = require('../i18n'),
|
|
utils = require('../utils'),
|
|
sitemapHandler = require('../data/xml/sitemap/handler'),
|
|
cacheControl = require('./cache-control'),
|
|
checkSSL = require('./check-ssl'),
|
|
decideIsAdmin = require('./decide-is-admin'),
|
|
redirectToSetup = require('./redirect-to-setup'),
|
|
ghostLocals = require('./ghost-locals'),
|
|
prettyURLs = require('./pretty-urls'),
|
|
serveSharedFile = require('./serve-shared-file'),
|
|
spamPrevention = require('./spam-prevention'),
|
|
staticTheme = require('./static-theme'),
|
|
themeHandler = require('./theme-handler'),
|
|
maintenance = require('./maintenance'),
|
|
errorHandler = require('./error-handler'),
|
|
versionMatch = require('./api/version-match'),
|
|
cors = require('./cors'),
|
|
validation = require('./validation'),
|
|
labs = require('./labs'),
|
|
helpers = require('../helpers'),
|
|
middleware,
|
|
setupMiddleware;
|
|
|
|
middleware = {
|
|
upload: multer({dest: tmpdir()}),
|
|
validation: validation,
|
|
cacheControl: cacheControl,
|
|
spamPrevention: spamPrevention,
|
|
api: {
|
|
errorHandler: errorHandler,
|
|
cors: cors,
|
|
labs: labs,
|
|
versionMatch: versionMatch,
|
|
maintenance: maintenance
|
|
}
|
|
};
|
|
|
|
setupMiddleware = function setupMiddleware(blogApp) {
|
|
debug('Middleware start');
|
|
|
|
var adminApp = express(),
|
|
adminHbs = hbs.create();
|
|
|
|
// ##Configuration
|
|
|
|
// enabled gzip compression by default
|
|
if (config.get('server').compress !== false) {
|
|
blogApp.use(compress());
|
|
}
|
|
|
|
// ## View engine
|
|
// set the view engine
|
|
blogApp.set('view engine', 'hbs');
|
|
|
|
// Create a hbs instance for admin and init view engine
|
|
adminApp.set('view engine', 'hbs');
|
|
adminApp.engine('hbs', adminHbs.express3({}));
|
|
debug('Views done');
|
|
|
|
// Load helpers
|
|
helpers.loadCoreHelpers(adminHbs);
|
|
debug('Helpers done');
|
|
|
|
// Make sure 'req.secure' is valid for proxied requests
|
|
// (X-Forwarded-Proto header will be checked, if present)
|
|
blogApp.enable('trust proxy');
|
|
|
|
/**
|
|
* request logging
|
|
*/
|
|
blogApp.use(function expressLogging(req, res, next) {
|
|
res.once('finish', function () {
|
|
logging.request({req: req, res: res, err: req.err});
|
|
});
|
|
|
|
next();
|
|
});
|
|
|
|
if (debug.enabled) {
|
|
// debug keeps a timer, so this is super useful
|
|
blogApp.use((function () {
|
|
var reqDebug = require('debug')('ghost:req');
|
|
return function debugLog(req, res, next) {
|
|
reqDebug('Request', req.originalUrl);
|
|
next();
|
|
};
|
|
})());
|
|
}
|
|
|
|
// Preload link headers
|
|
if (config.get('preloadHeaders')) {
|
|
blogApp.use(netjet({
|
|
cache: {
|
|
max: config.get('preloadHeaders')
|
|
}
|
|
}));
|
|
}
|
|
|
|
// This sets global res.locals which are needed everywhere
|
|
blogApp.use(ghostLocals);
|
|
|
|
// First determine whether we're serving admin or theme content
|
|
// @TODO refactor this horror away!
|
|
blogApp.use(decideIsAdmin);
|
|
|
|
// Theme middleware
|
|
// rightly or wrongly currently comes before theme static assets
|
|
// @TODO revisit where and when these are needed
|
|
blogApp.use(themeHandler.updateActiveTheme);
|
|
blogApp.use(themeHandler.configHbsForContext);
|
|
debug('Themes done');
|
|
|
|
// Static content/assets
|
|
// Favicon
|
|
blogApp.use(serveSharedFile('favicon.ico', 'image/x-icon', utils.ONE_DAY_S));
|
|
// Ghost-Url
|
|
blogApp.use(serveSharedFile('shared/ghost-url.js', 'application/javascript', utils.ONE_HOUR_S));
|
|
blogApp.use(serveSharedFile('shared/ghost-url.min.js', 'application/javascript', utils.ONE_HOUR_S));
|
|
// Serve sitemap.xsl file
|
|
blogApp.use(serveSharedFile('sitemap.xsl', 'text/xsl', utils.ONE_DAY_S));
|
|
// Serve robots.txt if not found in theme
|
|
blogApp.use(serveSharedFile('robots.txt', 'text/plain', utils.ONE_HOUR_S));
|
|
// Serve blog images using the storage adapter
|
|
blogApp.use('/content/images', storage.getStorage().serve());
|
|
|
|
// Admin assets
|
|
// Admin only config
|
|
blogApp.use('/ghost/assets', serveStatic(
|
|
config.get('paths').clientAssets,
|
|
{maxAge: utils.ONE_YEAR_MS}
|
|
));
|
|
|
|
// Theme static assets/files
|
|
blogApp.use(staticTheme());
|
|
debug('Static content done');
|
|
|
|
// Force SSL
|
|
// must happen AFTER asset loading and BEFORE routing
|
|
blogApp.use(checkSSL);
|
|
adminApp.set('views', config.get('paths').adminViews);
|
|
|
|
// setup middleware for internal apps
|
|
// @TODO: refactor this to be a proper app middleware hook for internal & external apps
|
|
config.get('internalApps').forEach(function (appName) {
|
|
var app = require(path.join(config.get('paths').internalAppPath, appName));
|
|
if (app.hasOwnProperty('setupMiddleware')) {
|
|
app.setupMiddleware(blogApp);
|
|
}
|
|
});
|
|
|
|
// site map - this should probably be refactored to be an internal app
|
|
sitemapHandler(blogApp);
|
|
debug('Internal apps done');
|
|
|
|
// Add in all trailing slashes & remove uppercase
|
|
// must happen AFTER asset loading and BEFORE routing
|
|
blogApp.use(prettyURLs);
|
|
|
|
// Body parsing
|
|
blogApp.use(bodyParser.json({limit: '1mb'}));
|
|
blogApp.use(bodyParser.urlencoded({extended: true, limit: '1mb'}));
|
|
|
|
// ### Caching
|
|
// Blog frontend is cacheable
|
|
blogApp.use(cacheControl('public'));
|
|
// Admin shouldn't be cached
|
|
adminApp.use(cacheControl('private'));
|
|
// API shouldn't be cached
|
|
blogApp.use(routes.apiBaseUri, cacheControl('private'));
|
|
|
|
debug('General middleware done');
|
|
|
|
// ### Routing
|
|
// Set up API routes
|
|
blogApp.use(routes.apiBaseUri, routes.api(middleware));
|
|
|
|
// Mount admin express app to /ghost and set up routes
|
|
adminApp.use(redirectToSetup);
|
|
adminApp.use(maintenance);
|
|
adminApp.use(routes.admin());
|
|
blogApp.use('/ghost', adminApp);
|
|
debug('Admin app & api done');
|
|
|
|
// send 503 error page in case of maintenance
|
|
blogApp.use(maintenance);
|
|
|
|
// Set up Frontend routes (including private blogging routes)
|
|
blogApp.use(routes.frontend());
|
|
|
|
// ### Error handlers
|
|
blogApp.use(function pageNotFound(req, res, next) {
|
|
next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
|
|
});
|
|
|
|
blogApp.use(errorHandler);
|
|
debug('Middleware end');
|
|
};
|
|
|
|
module.exports = setupMiddleware;
|
|
// Export middleware functions directly
|
|
module.exports.middleware = middleware;
|