diff --git a/README.md b/README.md index 4dfdf8d..fe8ce3f 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ You may also set `config.plugins.blankie` equal to `false` on a route to disable * `reflectedXss`: Value for the `reflected-xss` directive. Must be one of `'allow'`, `'block'` or `'filter'`. * `reportOnly`: Append '-Report-Only' to the name of the CSP header to enable report only mode. * `reportUri`: Value for the `report-uri` directive. This should be the path to a route that accepts CSP violation reports. +* `reportTo`: Name of the group defined in the `Report-to` header. This replaces `report-uri` in browsers that already support it. * `requireSriFor`: Value for `require-sri-for` directive. * `sandbox`: Values for the `sandbox` directive. May be a boolean or one of `'allow-forms'`, `'allow-same-origin'`, `'allow-scripts'` or `'allow-top-navigation'`. * `scriptSrc`: Values for the `script-src` directive. Defaults to `'self'`. diff --git a/lib/index.js b/lib/index.js index 47e172a..dda099e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -31,6 +31,7 @@ internals.arrayValues = [ internals.stringValues = [ 'reportUri', + 'reportTo', 'reflectedXss' ]; @@ -52,6 +53,7 @@ internals.directiveMap = { 'pluginTypes': 'plugin-types', 'reflectedXss': 'reflected-xss', 'reportUri': 'report-uri', + 'reportTo': 'report-to', 'requireSriFor': 'require-sri-for', 'scriptSrc': 'script-src', 'styleSrc': 'style-src', diff --git a/lib/schema.js b/lib/schema.js index 14f8cf6..31c594e 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -20,6 +20,7 @@ module.exports = Joi.object({ reflectedXss: Joi.string().valid('allow', 'block', 'filter'), reportOnly: Joi.boolean(), reportUri: Joi.string(), + reportTo: Joi.string(), requireSriFor: Joi.array().items(Joi.string()).single(), sandbox: [ Joi.array().items(Joi.string().valid('allow-forms', 'allow-same-origin', 'allow-scripts', 'allow-top-navigation')).single(), diff --git a/test/generic.js b/test/generic.js index 6280a8d..a1f6e66 100644 --- a/test/generic.js +++ b/test/generic.js @@ -279,7 +279,7 @@ describe('Generic headers', () => { expect(res.headers['content-security-policy']).to.contain('worker-src \'self\''); }); - it('sends report only headers when requested', async () => { + it('sends report only headers when requested using report-uri', async () => { const server = Hapi.server(); server.route(defaultRoute); @@ -303,6 +303,56 @@ describe('Generic headers', () => { expect(res.headers['content-security-policy-report-only']).to.contain('report-uri /csp_report'); }); + it('sends report only headers when requested using report-to', async () => { + + const server = Hapi.server(); + server.route(defaultRoute); + await server.register([Scooter, { + plugin: Blankie, + options: { + defaultSrc: 'self', + reportOnly: true, + reportTo: 'csp_report' + } + }]); + + const res = await server.inject({ + method: 'GET', + url: '/' + }); + + expect(res.statusCode).to.equal(200); + expect(res.headers).to.contain('content-security-policy-report-only'); + expect(res.headers['content-security-policy-report-only']).to.contain('default-src \'self\''); + expect(res.headers['content-security-policy-report-only']).to.contain('report-to csp_report'); + }); + + it('sends report only headers when requested using both report-uri and report-to', async () => { + + const server = Hapi.server(); + server.route(defaultRoute); + await server.register([Scooter, { + plugin: Blankie, + options: { + defaultSrc: 'self', + reportOnly: true, + reportUri: '/csp_report', + reportTo: 'csp_report' + } + }]); + + const res = await server.inject({ + method: 'GET', + url: '/' + }); + + expect(res.statusCode).to.equal(200); + expect(res.headers).to.contain('content-security-policy-report-only'); + expect(res.headers['content-security-policy-report-only']).to.contain('default-src \'self\''); + expect(res.headers['content-security-policy-report-only']).to.contain('report-uri /csp_report'); + expect(res.headers['content-security-policy-report-only']).to.contain('report-to csp_report'); // browser will only use report-to if it already supports it + }); + it('does not crash when responding with an error', async () => { const server = Hapi.server();