mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 09:52:06 +03:00
bd597db829
- This is part of the quest to separate the frontend and server & get rid of all the places where there are cross-requires - At the moment the settings cache is one big shared cache used by the frontend and server liberally - This change doesn't really solve the fundamental problems, as we still depend on events, and requires from inside frontend - However it allows us to control the misuse slightly better by getting rid of restricted requires and turning on that eslint ruleset
88 lines
3.2 KiB
JavaScript
88 lines
3.2 KiB
JavaScript
const fs = require('fs-extra');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
const config = require('../../../../shared/config');
|
|
const {blogIcon} = require('../../../lib/image');
|
|
const storage = require('../../../adapters/storage');
|
|
const urlUtils = require('../../../../shared/url-utils');
|
|
const settingsCache = require('../../../../shared/settings-cache');
|
|
|
|
let content;
|
|
|
|
const buildContentResponse = (ext, buf) => {
|
|
content = {
|
|
headers: {
|
|
'Content-Type': `image/${ext}`,
|
|
'Content-Length': buf.length,
|
|
ETag: `"${crypto.createHash('md5').update(buf, 'utf8').digest('hex')}"`,
|
|
'Cache-Control': `public, max-age=${config.get('caching:favicon:maxAge')}`
|
|
},
|
|
body: buf
|
|
};
|
|
|
|
return content;
|
|
};
|
|
|
|
// ### serveFavicon Middleware
|
|
// Handles requests to favicon.png and favicon.ico
|
|
function serveFavicon() {
|
|
let iconType;
|
|
let filePath;
|
|
|
|
return function serveFaviconMiddleware(req, res, next) {
|
|
if (req.path.match(/^\/favicon\.(ico|png)/i)) {
|
|
// CASE: favicon is default
|
|
// confusing: if you upload an icon, it's same logic as storing images
|
|
// we store as /content/images, because this is the url path images get requested via the browser
|
|
// we are using an express route to skip /content/images and the result is a image path
|
|
// based on config.getContentPath('images') + req.path
|
|
// in this case we don't use path rewrite, that's why we have to make it manually
|
|
filePath = blogIcon.getIconPath();
|
|
|
|
let originalExtension = path.extname(filePath).toLowerCase();
|
|
const requestedExtension = path.extname(req.path).toLowerCase();
|
|
|
|
// CASE: custom favicon exists, load it from local file storage
|
|
if (settingsCache.get('icon')) {
|
|
// depends on the uploaded icon extension
|
|
if (originalExtension !== requestedExtension) {
|
|
return res.redirect(302, urlUtils.urlFor({relativeUrl: `/favicon${originalExtension}`}));
|
|
}
|
|
|
|
storage.getStorage()
|
|
.read({path: filePath})
|
|
.then((buf) => {
|
|
iconType = blogIcon.getIconType();
|
|
content = buildContentResponse(iconType, buf);
|
|
|
|
res.writeHead(200, content.headers);
|
|
res.end(content.body);
|
|
})
|
|
.catch(next);
|
|
} else {
|
|
originalExtension = path.extname(filePath).toLowerCase();
|
|
|
|
// CASE: always redirect to .ico for default icon
|
|
if (originalExtension !== requestedExtension) {
|
|
return res.redirect(302, urlUtils.urlFor({relativeUrl: '/favicon.ico'}));
|
|
}
|
|
|
|
fs.readFile(filePath, (err, buf) => {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
content = buildContentResponse('x-icon', buf);
|
|
|
|
res.writeHead(200, content.headers);
|
|
res.end(content.body);
|
|
});
|
|
}
|
|
} else {
|
|
return next();
|
|
}
|
|
};
|
|
}
|
|
|
|
module.exports = serveFavicon;
|