diff --git a/README.md b/README.md index c42d4a7..604af02 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ app.listen(80, function () { * `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed. * `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted. * `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted. +* `allowPrivateNetwork`: Configures the **Access-Control-Allow-Private-Network**. Set to `false` to disable Private Network Requests, otherwise it is allowed. * `preflightContinue`: Pass the CORS preflight response to the next handler. * `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`. diff --git a/lib/index.js b/lib/index.js index ad899ca..066202a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -9,7 +9,8 @@ origin: '*', methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', preflightContinue: false, - optionsSuccessStatus: 204 + optionsSuccessStatus: 204, + allowPrivateNetwork: false, }; function isString(s) { @@ -141,6 +142,16 @@ return null; } + function configurePrivateNetworkAccess(options, req) { + if (req.headers['access-control-request-private-network'] === 'true' && options.allowPrivateNetwork) { + return { + key: 'Access-Control-Allow-Private-Network', + value: 'true' + }; + } + return null; + } + function applyHeaders(headers, res) { for (var i = 0, n = headers.length; i < n; i++) { var header = headers[i]; @@ -168,6 +179,7 @@ headers.push(configureAllowedHeaders(options, req)); headers.push(configureMaxAge(options)) headers.push(configureExposedHeaders(options)) + headers.push(configurePrivateNetworkAccess(options, req)) applyHeaders(headers, res); if (options.preflightContinue) { diff --git a/test/test.js b/test/test.js index f2a2e94..5262f9f 100644 --- a/test/test.js +++ b/test/test.js @@ -630,6 +630,67 @@ var util = require('util') // act cors()(req, res, next); }); + + it('allows private network requests when allowPrivateNetwork is true', function (done) { + // arrange + var req, res, options, cb; + options = { + allowPrivateNetwork: true, + }; + req = fakeRequest('OPTIONS', {'access-control-request-private-network': 'true'}); + res = fakeResponse(); + cb = after(1, done) + + res.on('finish', function () { + assert.equal(res.getHeader('Access-Control-Allow-Private-Network'), 'true') + cb() + }) + + // act + cors(options)(req, res, function (err) { + cb(err || new Error('should not be called')) + }); + }); + + it('denies private network requests when allowPrivateNetwork is false', function (done) { + // arrange + var req, res, options, cb; + options = { + allowPrivateNetwork: false, + }; + req = fakeRequest('OPTIONS', {'access-control-request-private-network': 'true'}); + res = fakeResponse(); + cb = after(1, done) + + res.on('finish', function () { + assert.equal(res.getHeader('Access-Control-Allow-Private-Network'), undefined) + cb() + }) + + // act + cors(options)(req, res, function (err) { + cb(err || new Error('should not be called')) + }); + }); + + it('denies private network requests when no options are set', function (done) { + // arrange + var req, res, options, cb; + options = {}; + req = fakeRequest('OPTIONS', {'access-control-request-private-network': 'true'}); + res = fakeResponse(); + cb = after(1, done) + + res.on('finish', function () { + assert.equal(res.getHeader('Access-Control-Allow-Private-Network'), undefined) + cb() + }) + + // act + cors(options)(req, res, function (err) { + cb(err || new Error('should not be called')) + }); + }); }); describe('passing a function to build options', function () {