Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Commit

Permalink
fix(csp-report): add application/csp-report content type support (#1038)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Mallimo <matthew.c.mallimo@aexp.com>
  • Loading branch information
JAdshead and Matthew-Mallimo authored Jun 29, 2023
1 parent a82f6d2 commit 077fbc3
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 14 deletions.
2 changes: 1 addition & 1 deletion __tests__/integration/__snapshots__/one-app.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ exports[`Tests that require Docker setup one-app successfully started metrics ha

exports[`Tests that require Docker setup one-app successfully started one-app server provides reporting routes client reported errors logs errors when reported to /_/report/errors 1`] = `"reported client error"`;

exports[`Tests that require Docker setup one-app successfully started one-app server provides reporting routes csp-violations reported to server logs violations reported to /_/report/errors 1`] = `"CSP Violation: {\\n \\"csp-report\\": {\\n \\"document-uri\\": \\"bad.example.com"`;
exports[`Tests that require Docker setup one-app successfully started one-app server provides reporting routes csp-violations reported to server logs violations reported to /_/report/errors 1`] = `"CSP Violation: {\\"csp-report\\":{\\"document-uri\\":\\"bad.example.com"`;
2 changes: 1 addition & 1 deletion __tests__/integration/one-app.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ describe('Tests that require Docker setup', () => {
...defaultFetchOptions,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Type': 'application/csp-report',
},
body: JSON.stringify({
'csp-report': {
Expand Down
124 changes: 124 additions & 0 deletions __tests__/server/ssrServer-requests.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright 2023 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import ssrServer from '../../src/server/ssrServer';

const { NODE_ENV } = process.env;
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

jest.mock('fastify-metrics', () => (_req, _opts, done) => done());

describe('ssrServer route testing', () => {
afterAll(() => {
process.env.NODE_ENV = NODE_ENV;
});

beforeEach(() => {
jest.clearAllMocks();
});

test('/_/status', async () => {
const server = await ssrServer();
const resp = await server.inject({
method: 'GET',
url: '/_/status',
});

expect(resp.statusCode).toEqual(200);
expect(resp.body).toEqual('OK');
});

describe('/_/report/security/csp-violation', () => {
describe('production', () => {
let server;
beforeAll(async () => {
process.env.NODE_ENV = 'production';
server = await ssrServer();
});

test('with csp-report', async () => {
const resp = await server.inject({
method: 'POST',
url: '/_/report/security/csp-violation',
headers: {
'Content-Type': 'application/csp-report',
},
payload: JSON.stringify({
'csp-report': {
'document-uri': 'bad.example.com',
},
}),
});
expect(warnSpy).toHaveBeenCalledWith('CSP Violation: {"csp-report":{"document-uri":"bad.example.com"}}');
expect(resp.statusCode).toEqual(204);
});

test('when csp-report is not provided', async () => {
const resp = await server.inject({
method: 'POST',
url: '/_/report/security/csp-violation',
headers: {
'Content-Type': 'application/csp-report',
},
});
expect(warnSpy).toHaveBeenCalledWith('CSP Violation: No data received!');
expect(resp.statusCode).toEqual(204);
});
});

describe('development', () => {
let server;
beforeAll(async () => {
process.env.NODE_ENV = 'development';
server = await ssrServer();
});

test('with csp-report', async () => {
const resp = await server.inject({
method: 'POST',
url: '/_/report/security/csp-violation',
headers: {
'Content-Type': 'application/csp-report',
},
payload: JSON.stringify({
'csp-report': {
'document-uri': 'bad.example.com',
'violated-directive': 'script-src',
'blocked-uri': 'blockedUri.example.com',
'line-number': '123',
'column-number': '432',
'source-file': 'sourceFile.js',
},
}),
});
expect(warnSpy).toHaveBeenCalledWith('CSP Violation: sourceFile.js:123:432 on page bad.example.com violated the script-src policy via blockedUri.example.com');
expect(resp.statusCode).toEqual(204);
});

test('when no csp-report', async () => {
const resp = await server.inject({
method: 'POST',
url: '/_/report/security/csp-violation',
headers: {
'Content-Type': 'application/csp-report',
},
});
expect(warnSpy).toHaveBeenCalledWith('CSP Violation reported, but no data received');
expect(resp.statusCode).toEqual(204);
});
});
});
});
18 changes: 10 additions & 8 deletions __tests__/server/ssrServer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe('ssrServer', () => {
setNotFoundHandler,
setErrorHandler,
ready,
addContentTypeParser: jest.fn(),
}));
});

Expand Down Expand Up @@ -325,7 +326,10 @@ describe('ssrServer', () => {
}, null, jest.fn());

const request = {
body: {},
headers: {
'Content-Type': 'application/csp-report',
},
body: JSON.stringify({}),
};
const reply = {
status: jest.fn(() => reply),
Expand Down Expand Up @@ -353,7 +357,7 @@ describe('ssrServer', () => {
}, null, jest.fn());

const request = {
body: {
body: JSON.stringify({
'csp-report': {
'document-uri': 'document-uri',
'violated-directive': 'violated-directive',
Expand All @@ -362,7 +366,7 @@ describe('ssrServer', () => {
'column-number': 'column-number',
'source-file': 'source-file',
},
},
}),
};
const reply = {
status: jest.fn(() => reply),
Expand Down Expand Up @@ -450,9 +454,9 @@ describe('ssrServer', () => {

const request = {
headers: {},
body: {
body: JSON.stringify({
unit: 'testing',
},
}),
};
const reply = {
status: jest.fn(() => reply),
Expand All @@ -462,9 +466,7 @@ describe('ssrServer', () => {
post.mock.calls[0][1](request, reply);

expect(post.mock.calls[0][0]).toEqual('/_/report/security/csp-violation');
expect(console.warn).toHaveBeenCalledWith(`CSP Violation: {
"unit": "testing"
}`);
expect(console.warn).toHaveBeenCalledWith('CSP Violation: {"unit":"testing"}');
expect(reply.status).toHaveBeenCalledWith(204);
expect(reply.send).toHaveBeenCalled();
});
Expand Down
11 changes: 7 additions & 4 deletions src/server/ssrServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,19 @@ export async function createApp(opts = {}) {
done();
});

// PWA
fastify.addContentTypeParser('application/csp-report', { parseAs: 'string' }, (req, body, doneParsing) => {
doneParsing(null, body);
});

// pwa manifest & Report routes for csp and errors
fastify.register((instance, _opts, done) => {
instance.register(addCacheHeaders);
instance.register(csp);

instance.get('/_/pwa/manifest.webmanifest', webManifestMiddleware);

if (nodeEnvIsDevelopment()) {
instance.post('/_/report/security/csp-violation', (request, reply) => {
const violation = request.body && request.body['csp-report'];
const violation = request.body && JSON.parse(request.body)['csp-report'];
if (!violation) {
console.warn('CSP Violation reported, but no data received');
} else {
Expand All @@ -131,7 +134,7 @@ export async function createApp(opts = {}) {
});
} else {
instance.post('/_/report/security/csp-violation', (request, reply) => {
const violation = request.body ? JSON.stringify(request.body, null, 2) : 'No data received!';
const violation = request.body ? request.body : 'No data received!';
console.warn(`CSP Violation: ${violation}`);
reply.status(204).send();
});
Expand Down

0 comments on commit 077fbc3

Please sign in to comment.