mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
fix(security): cache-control on all pages using setupPageRoute or setupApiRoute, and 404 controllers.
This commit also reverts e39cdd490b
This commit is contained in:
@@ -55,6 +55,7 @@ exports.send404 = async function (req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await middleware.inhibitCacheAsync(req, res);
|
||||||
await middleware.buildHeaderAsync(req, res);
|
await middleware.buildHeaderAsync(req, res);
|
||||||
await res.render('404', {
|
await res.render('404', {
|
||||||
path: validator.escape(path),
|
path: validator.escape(path),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const os = require('os');
|
const os = require('os');
|
||||||
const winston = require('winston');
|
const winston = require('winston');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const util = require('util');
|
||||||
|
|
||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const languages = require('../languages');
|
const languages = require('../languages');
|
||||||
@@ -108,4 +109,13 @@ module.exports = function (middleware) {
|
|||||||
return [defaultLang];
|
return [defaultLang];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
middleware.inhibitCache = (req, res, next) => {
|
||||||
|
if (req.loggedIn) {
|
||||||
|
res.set('cache-control', 'private');
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
middleware.inhibitCacheAsync = util.promisify(middleware.inhibitCache);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ function _handleArgs(middleware, middlewares, controller) {
|
|||||||
middleware.authenticateRequest,
|
middleware.authenticateRequest,
|
||||||
middleware.maintenanceMode,
|
middleware.maintenanceMode,
|
||||||
middleware.registrationComplete,
|
middleware.registrationComplete,
|
||||||
|
middleware.inhibitCache,
|
||||||
middleware.pluginHooks,
|
middleware.pluginHooks,
|
||||||
...middlewares,
|
...middlewares,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const nconf = require('nconf');
|
||||||
|
const request = require('request-promise-native');
|
||||||
const db = require('./mocks/databasemock');
|
const db = require('./mocks/databasemock');
|
||||||
const middleware = require('../src/middleware');
|
const middleware = require('../src/middleware');
|
||||||
const user = require('../src/user');
|
const user = require('../src/user');
|
||||||
const groups = require('../src/groups');
|
const groups = require('../src/groups');
|
||||||
|
const utils = require('../src/utils');
|
||||||
|
|
||||||
|
const helpers = require('./helpers');
|
||||||
|
|
||||||
describe('Middlewares', () => {
|
describe('Middlewares', () => {
|
||||||
|
describe('expose', () => {
|
||||||
let adminUid;
|
let adminUid;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@@ -14,7 +20,6 @@ describe('Middlewares', () => {
|
|||||||
await groups.join('administrators', adminUid);
|
await groups.join('administrators', adminUid);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('expose', () => {
|
|
||||||
it('should expose res.locals.isAdmin = false', (done) => {
|
it('should expose res.locals.isAdmin = false', (done) => {
|
||||||
const resMock = { locals: {} };
|
const resMock = { locals: {} };
|
||||||
middleware.exposeAdmin({}, resMock, () => {
|
middleware.exposeAdmin({}, resMock, () => {
|
||||||
@@ -94,5 +99,93 @@ describe('Middlewares', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.inhibitCache (cache-control header)', () => {
|
||||||
|
let uid;
|
||||||
|
let jar;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
uid = await user.create({ username: 'testuser', password: '123456' });
|
||||||
|
({ jar } = await helpers.loginUser('testuser', '123456'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be absent on non-existent routes, for guests', async () => {
|
||||||
|
const res = await request(`${nconf.get('url')}/${utils.generateUUID()}`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 404);
|
||||||
|
assert(!Object.keys(res.headers).includes('cache-control'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be set to "private" on non-existent routes, for logged in users', async () => {
|
||||||
|
const res = await request(`${nconf.get('url')}/${utils.generateUUID()}`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
jar,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 404);
|
||||||
|
assert(Object.keys(res.headers).includes('cache-control'));
|
||||||
|
assert.strictEqual(res.headers['cache-control'], 'private');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be absent on regular routes, for guests', async () => {
|
||||||
|
const res = await request(nconf.get('url'), {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 200);
|
||||||
|
assert(!Object.keys(res.headers).includes('cache-control'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be absent on api routes, for guests', async () => {
|
||||||
|
const res = await request(`${nconf.get('url')}/api`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 200);
|
||||||
|
assert(!Object.keys(res.headers).includes('cache-control'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be set to "private" on regular routes, for logged-in users', async () => {
|
||||||
|
const res = await request(nconf.get('url'), {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
jar,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 200);
|
||||||
|
assert(Object.keys(res.headers).includes('cache-control'));
|
||||||
|
assert.strictEqual(res.headers['cache-control'], 'private');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be set to "private" on api routes, for logged-in users', async () => {
|
||||||
|
const res = await request(`${nconf.get('url')}/api`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
jar,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 200);
|
||||||
|
assert(Object.keys(res.headers).includes('cache-control'));
|
||||||
|
assert.strictEqual(res.headers['cache-control'], 'private');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be set to "private" on apiv3 routes, for logged-in users', async () => {
|
||||||
|
const res = await request(`${nconf.get('url')}/api/v3/users/${uid}`, {
|
||||||
|
simple: false,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
jar,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.statusCode, 200);
|
||||||
|
assert(Object.keys(res.headers).includes('cache-control'));
|
||||||
|
assert.strictEqual(res.headers['cache-control'], 'private');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user