From 14f6e74bad6df3f3a130aa79bc322f4798c61127 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
Date: Wed, 6 Jun 2018 13:11:43 -0400
Subject: [PATCH] closes #6556
---
.../en-GB/admin/settings/advanced.json | 2 +
src/middleware/headers.js | 20 +++++++
src/views/admin/settings/advanced.tpl | 7 +++
test/meta.js | 60 +++++++++++++++++++
4 files changed, 89 insertions(+)
diff --git a/public/language/en-GB/admin/settings/advanced.json b/public/language/en-GB/admin/settings/advanced.json
index 8da7b1c46a..16eae5a8bd 100644
--- a/public/language/en-GB/admin/settings/advanced.json
+++ b/public/language/en-GB/admin/settings/advanced.json
@@ -6,7 +6,9 @@
"headers.allow-from": "Set ALLOW-FROM to Place NodeBB in an iFrame",
"headers.powered-by": "Customise the \"Powered By\" header sent by NodeBB",
"headers.acao": "Access-Control-Allow-Origin",
+ "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression",
"headers.acao-help": "To deny access to all sites, leave empty",
+ "headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty",
"headers.acac": "Access-Control-Allow-Credentials",
"headers.acam": "Access-Control-Allow-Methods",
"headers.acah": "Access-Control-Allow-Headers",
diff --git a/src/middleware/headers.js b/src/middleware/headers.js
index 60af68a894..f700ac4017 100644
--- a/src/middleware/headers.js
+++ b/src/middleware/headers.js
@@ -1,6 +1,7 @@
'use strict';
var os = require('os');
+var winston = require('winston');
var meta = require('../meta');
@@ -24,6 +25,25 @@ module.exports = function (middleware) {
}
}
+ if (meta.config['access-control-allow-origin-regex']) {
+ var originsRegex = meta.config['access-control-allow-origin-regex'].split(',');
+ originsRegex = originsRegex.map(function (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(function (regex) {
+ if (regex && regex.test(req.get('origin'))) {
+ headers['Access-Control-Allow-Origin'] = encodeURI(req.get('origin'));
+ }
+ });
+ }
+
if (meta.config['access-control-allow-credentials']) {
headers['Access-Control-Allow-Credentials'] = meta.config['access-control-allow-credentials'];
}
diff --git a/src/views/admin/settings/advanced.tpl b/src/views/admin/settings/advanced.tpl
index b2721ff0bd..958ae73c3f 100644
--- a/src/views/admin/settings/advanced.tpl
+++ b/src/views/admin/settings/advanced.tpl
@@ -40,6 +40,13 @@
[[admin/settings/advanced:headers.acao-help]]
+
diff --git a/test/meta.js b/test/meta.js
index 008be48975..5fe417ca2f 100644
--- a/test/meta.js
+++ b/test/meta.js
@@ -356,5 +356,65 @@ describe('meta', function () {
done(err);
});
});
+
+ it('should set proper Access-Control-Allow-Origin header', function (done) {
+ var jar = request.jar();
+ var oldValue = meta.config['access-control-allow-origin-regex'];
+ meta.config['access-control-allow-origin-regex'] = 'match\\.this\\..+\\.domain.com, mydomain\\.com';
+ request.get(nconf.get('url') + '/api/search?term=bug', {
+ form: {
+ },
+ json: true,
+ jar: jar,
+ headers: {
+ origin: 'match.this.anything123.domain.com',
+ },
+ }, function (err, response, body) {
+ assert.ifError(err);
+ assert.equal(response.headers['access-control-allow-origin'], 'match.this.anything123.domain.com');
+ meta.config['access-control-allow-origin-regex'] = oldValue;
+ done(err);
+ });
+ });
+
+ it('Access-Control-Allow-Origin header should be empty if origin does not match', function (done) {
+ var jar = request.jar();
+ var oldValue = meta.config['access-control-allow-origin-regex'];
+ meta.config['access-control-allow-origin-regex'] = 'match\\.this\\..+\\.domain.com, mydomain\\.com';
+ request.get(nconf.get('url') + '/api/search?term=bug', {
+ form: {
+ },
+ json: true,
+ jar: jar,
+ headers: {
+ origin: 'notallowed.com',
+ },
+ }, function (err, response, body) {
+ assert.ifError(err);
+ assert.equal(response.headers['access-control-allow-origin'], undefined);
+ meta.config['access-control-allow-origin-regex'] = oldValue;
+ done(err);
+ });
+ });
+
+ it('should not error with invalid regexp', function (done) {
+ var jar = request.jar();
+ var oldValue = meta.config['access-control-allow-origin-regex'];
+ meta.config['access-control-allow-origin-regex'] = '[match\\.this\\..+\\.domain.com, mydomain\\.com';
+ request.get(nconf.get('url') + '/api/search?term=bug', {
+ form: {
+ },
+ json: true,
+ jar: jar,
+ headers: {
+ origin: 'mydomain.com',
+ },
+ }, function (err, response, body) {
+ assert.ifError(err);
+ assert.equal(response.headers['access-control-allow-origin'], 'mydomain.com');
+ meta.config['access-control-allow-origin-regex'] = oldValue;
+ done(err);
+ });
+ });
});
});