-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
headers.js
116 lines (99 loc) · 3.44 KB
/
headers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
'use strict';
const os = require('os');
const winston = require('winston');
const _ = require('lodash');
const meta = require('../meta');
const languages = require('../languages');
const helpers = require('./helpers');
const plugins = require('../plugins');
module.exports = function (middleware) {
middleware.addHeaders = helpers.try((req, res, next) => {
const headers = {
'X-Powered-By': encodeURI(meta.config['powered-by'] || 'NodeBB'),
'Access-Control-Allow-Methods': encodeURI(meta.config['access-control-allow-methods'] || ''),
'Access-Control-Allow-Headers': encodeURI(meta.config['access-control-allow-headers'] || ''),
};
if (meta.config['csp-frame-ancestors']) {
headers['Content-Security-Policy'] = `frame-ancestors ${meta.config['csp-frame-ancestors']}`;
if (meta.config['csp-frame-ancestors'] === '\'none\'') {
headers['X-Frame-Options'] = 'DENY';
}
} else {
headers['Content-Security-Policy'] = 'frame-ancestors \'self\'';
headers['X-Frame-Options'] = 'SAMEORIGIN';
}
if (meta.config['access-control-allow-origin']) {
let origins = meta.config['access-control-allow-origin'].split(',');
origins = origins.map(origin => origin && origin.trim());
if (origins.includes(req.get('origin'))) {
headers['Access-Control-Allow-Origin'] = encodeURI(req.get('origin'));
headers.Vary = headers.Vary ? `${headers.Vary}, Origin` : 'Origin';
}
}
if (meta.config['access-control-allow-origin-regex']) {
let originsRegex = meta.config['access-control-allow-origin-regex'].split(',');
originsRegex = originsRegex.map((origin) => {
try {
origin = new RegExp(origin.trim());
} catch (err) {
winston.error(`[middleware.addHeaders] Invalid RegExp For access-control-allow-origin ${origin}`);
origin = null;
}
return origin;
});
originsRegex.forEach((regex) => {
if (regex && regex.test(req.get('origin'))) {
headers['Access-Control-Allow-Origin'] = encodeURI(req.get('origin'));
headers.Vary = headers.Vary ? `${headers.Vary}, Origin` : 'Origin';
}
});
}
if (meta.config['permissions-policy']) {
headers['Permissions-Policy'] = meta.config['permissions-policy'];
}
if (meta.config['access-control-allow-credentials']) {
headers['Access-Control-Allow-Credentials'] = meta.config['access-control-allow-credentials'];
}
if (process.env.NODE_ENV === 'development') {
headers['X-Upstream-Hostname'] = os.hostname().replace(/[^0-9A-Za-z-.]/g, '');
}
for (const [key, value] of Object.entries(headers)) {
if (value) {
res.setHeader(key, value);
}
}
next();
});
middleware.autoLocale = helpers.try(async (req, res, next) => {
await plugins.hooks.fire('filter:middleware.autoLocale', {
req: req,
res: res,
});
if (req.query.lang) {
const langs = await listCodes();
if (!langs.includes(req.query.lang)) {
req.query.lang = meta.config.defaultLang;
}
return next();
}
if (meta.config.autoDetectLang && req.uid === 0) {
const langs = await listCodes();
const lang = req.acceptsLanguages(langs);
if (!lang) {
return next();
}
req.query.lang = lang;
}
next();
});
async function listCodes() {
const defaultLang = meta.config.defaultLang || 'en-GB';
try {
const codes = await languages.listCodes();
return _.uniq([defaultLang, ...codes]);
} catch (err) {
winston.error(`[middleware/autoLocale] Could not retrieve languages codes list! ${err.stack}`);
return [defaultLang];
}
}
};