Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ghost/core/core/frontend/services/theme-engine/active.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* No properties marked with an _ should be used directly.
*
*/
const fs = require('fs-extra');
const join = require('path').join;

const _ = require('lodash');
Expand Down Expand Up @@ -54,6 +55,8 @@ class ActiveTheme {
this._config = themeConfig.create(this._packageInfo);

this.initI18n();

this._hasRobotsTxt = fs.existsSync(join(this._path, 'robots.txt'));
}

get name() {
Expand Down Expand Up @@ -84,6 +87,10 @@ class ActiveTheme {
return this._templates.indexOf(templateName) > -1;
}

hasRobotsTxt() {
return this._hasRobotsTxt;
}

updateTemplateOptions(options) {
engine.updateTemplateOptions(_.merge({}, engine.getTemplateOptions(), options));
}
Expand Down
1 change: 0 additions & 1 deletion ghost/core/core/frontend/web/middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ module.exports = {
frontendCaching: require('./frontend-caching'),
handleImageSizes: require('./handle-image-sizes'),
redirectGhostToAdmin: require('./redirect-ghost-to-admin'),
servePublicFile: require('./serve-public-file'),
staticTheme: require('./static-theme')
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const errors = require('@tryghost/errors');
const config = require('../../../shared/config');
const urlUtils = require('../../../shared/url-utils');
const tpl = require('@tryghost/tpl');
const {cardAssets} = require('../../services/assets-minification');
const themeEngine = require('../../services/theme-engine');
const settingsCache = require('../../../shared/settings-cache');

const messages = {
imageNotFound: 'Image not found',
Expand Down Expand Up @@ -99,7 +102,6 @@ function createPublicFileMiddleware(location, file, mime, maxAge, options = {})
};
}

// ### servePublicFile Middleware
// Handles requests to robots.txt and favicon.ico (and caches them)
function servePublicFile(location, file, type, maxAge, options = {}) {
const publicFileMiddleware = createPublicFileMiddleware(location, file, type, maxAge, options);
Expand All @@ -113,6 +115,47 @@ function servePublicFile(location, file, type, maxAge, options = {}) {
};
}

module.exports = servePublicFile;
// Handles requests to public static files served by Ghost
function servePublicFiles(siteApp) {
// Serve sitemap.xsl
siteApp.get('/sitemap.xsl', createPublicFileMiddleware('static', 'sitemap.xsl', 'text/xsl', config.get('caching:sitemapXSL:maxAge')));

// Serve stylesheets for default templates
siteApp.get('/public/ghost.css', createPublicFileMiddleware('static', 'public/ghost.css', 'text/css', config.get('caching:publicAssets:maxAge')));
siteApp.get('/public/ghost.min.css', createPublicFileMiddleware('static', 'public/ghost.min.css', 'text/css', config.get('caching:publicAssets:maxAge')));

// Traffic analytics tracking script
siteApp.get('/public/ghost-stats.min.js', createPublicFileMiddleware('static', 'public/ghost-stats.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Card assets (built on the fly)
siteApp.get('/public/cards.min.css', cardAssets.serveMiddleware(), createPublicFileMiddleware('built', 'public/cards.min.css', 'text/css', config.get('caching:publicAssets:maxAge')));
siteApp.get('/public/cards.min.js', cardAssets.serveMiddleware(), createPublicFileMiddleware('built', 'public/cards.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Comment counts
siteApp.get('/public/comment-counts.min.js', createPublicFileMiddleware('static', 'public/comment-counts.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Member attribution
siteApp.get('/public/member-attribution.min.js', createPublicFileMiddleware('static', 'public/member-attribution.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Recommendations well-known
siteApp.get('/.well-known/recommendations.json', createPublicFileMiddleware('built', '.well-known/recommendations.json', 'application/json', config.get('caching:publicAssets:maxAge'), {disableServerCache: true}));

// Serve robots.txt if not found in theme (and blog is not private)
const defaultRobotsTxtMiddleware = createPublicFileMiddleware('static', 'robots.txt', 'text/plain', config.get('caching:robotstxt:maxAge'));
siteApp.get('/robots.txt', function serveRobotsTxt(req, res, next) {
// If private blogging is enabled, let filterPrivateRoutes handle it
if (settingsCache.get('is_private')) {
return next();
}

const activeTheme = themeEngine.getActive();
if (activeTheme?.hasRobotsTxt()) {
return next();
}
return defaultRobotsTxtMiddleware(req, res, next);
});
}

module.exports = servePublicFiles;
module.exports.servePublicFile = servePublicFile;
module.exports.createPublicFileMiddleware = createPublicFileMiddleware;
29 changes: 3 additions & 26 deletions ghost/core/core/frontend/web/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ const storage = require('../../server/adapters/storage');
const urlUtils = require('../../shared/url-utils');
const sitemapHandler = require('../services/sitemap/handler');
const serveFavicon = require('./routers/serve-favicon');
const servePublicFiles = require('./routers/serve-public-file');
const themeEngine = require('../services/theme-engine');
const themeMiddleware = themeEngine.middleware;
const membersService = require('../../server/services/members');
const offersService = require('../../server/services/offers');
const customRedirects = require('../../server/services/custom-redirects');
const linkRedirects = require('../../server/services/link-redirection');
const {cardAssets} = require('../services/assets-minification');
const siteRoutes = require('./routes');
const shared = require('../../server/web/shared');
const errorHandler = require('@tryghost/mw-error-handler');
Expand Down Expand Up @@ -65,25 +65,8 @@ module.exports = function setupSiteApp(routerConfig) {
// Favicon
serveFavicon(siteApp);

// Serve sitemap.xsl file
siteApp.use(mw.servePublicFile('static', 'sitemap.xsl', 'text/xsl', config.get('caching:sitemapXSL:maxAge')));

// Serve stylesheets for default templates
siteApp.use(mw.servePublicFile('static', 'public/ghost.css', 'text/css', config.get('caching:publicAssets:maxAge')));
siteApp.use(mw.servePublicFile('static', 'public/ghost.min.css', 'text/css', config.get('caching:publicAssets:maxAge')));

// Traffic analytics tracking script
siteApp.use(mw.servePublicFile('static', 'public/ghost-stats.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Card assets
siteApp.use(cardAssets.serveMiddleware(), mw.servePublicFile('built', 'public/cards.min.css', 'text/css', config.get('caching:publicAssets:maxAge')));
siteApp.use(cardAssets.serveMiddleware(), mw.servePublicFile('built', 'public/cards.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Comment counts
siteApp.use(mw.servePublicFile('static', 'public/comment-counts.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));

// Member attribution
siteApp.use(mw.servePublicFile('static', 'public/member-attribution.min.js', 'application/javascript', config.get('caching:publicAssets:maxAge')));
// Public files (sitemap.xsl, stylesheets, scripts, etc.)
servePublicFiles(siteApp);

// Serve site images using the storage adapter
siteApp.use(STATIC_IMAGE_URL_PREFIX, mw.handleImageSizes, storage.getStorage('images').serve());
Expand All @@ -101,9 +84,6 @@ module.exports = function setupSiteApp(routerConfig) {
}
);

// Recommendations well-known
siteApp.use(mw.servePublicFile('built', '.well-known/recommendations.json', 'application/json', config.get('caching:publicAssets:maxAge'), {disableServerCache: true}));

// setup middleware for internal apps
// @TODO: refactor this to be a proper app middleware hook for internal apps
config.get('apps:internal').forEach((appName) => {
Expand All @@ -117,9 +97,6 @@ module.exports = function setupSiteApp(routerConfig) {
// Theme static assets/files
siteApp.use(mw.staticTheme());

// Serve robots.txt if not found in theme
siteApp.use(mw.servePublicFile('static', 'robots.txt', 'text/plain', config.get('caching:robotstxt:maxAge')));

debug('Static content done');

// site map - this should probably be refactored to be an internal app
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const should = require('should');
const sinon = require('sinon');
const fs = require('fs-extra');
const servePublicFile = require('../../../../../core/frontend/web/middleware/serve-public-file');
const {servePublicFile} = require('../../../../../core/frontend/web/routers/serve-public-file');

describe('servePublicFile', function () {
let res;
Expand Down