Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DUMMY preview rebase #2377

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const eligibilityCookie = new EligibilityCookie();
const caseTypes = require('app/utils/CaseTypes');
const featureToggles = require('app/featureToggles');
const sanitizeRequestBody = require('app/middleware/sanitizeRequestBody');
const setSessionLanguage = require('app/middleware/setSessionLanguage');
const isEmpty = require('lodash').isEmpty;
const setupHealthCheck = require('app/utils/setupHealthCheck');

Expand Down Expand Up @@ -185,6 +186,10 @@ exports.init = function (isA11yTest = false, a11yTestSession = {}, ftValue) {
app.use(nocache());
app.use(helmet.xssFilter({setOnOldIE: true}));

app.use(helmet.strictTransportSecurity({
maxAge: 31536000,
}));

const caching = {cacheControl: true, setHeaders: (res) => res.setHeader('Cache-Control', 'max-age=604800')};

// Middleware to serve static assets
Expand Down Expand Up @@ -243,19 +248,9 @@ exports.init = function (isA11yTest = false, a11yTestSession = {}, ftValue) {
next();
});

app.use((req, res, next) => {
if (!req.session.language) {
req.session.language = 'en';
}

if (req.query) {
if (req.query.lng && config.languages.includes(req.query.lng)) {
req.session.language = req.query.lng;
} else if (req.query.locale && config.languages.includes(req.query.locale)) {
req.session.language = req.query.locale;
}
}
app.use(setSessionLanguage);

app.use((req, res, next) => {
if (isA11yTest && !isEmpty(a11yTestSession)) {
req.session = Object.assign(req.session, a11yTestSession);
}
Expand Down
36 changes: 36 additions & 0 deletions app/middleware/setSessionLanguage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const config = require('config');

const isLanguageAvailable = (lang) => {
return config.languages.includes(lang);
};

const getAvailableLanguageFromQueryParams = (queryParam) => {
if (queryParam) {
if (!Array.isArray(queryParam)) {
queryParam = [queryParam];
}

return queryParam.find(isLanguageAvailable);
}
};

const setLanguageForSession = (req, res, next) => {
if (!req.session.language) {
req.session.language = 'en';
}

if (req.query) {
const fromLng = getAvailableLanguageFromQueryParams(req.query.lng);
const fromLocale = getAvailableLanguageFromQueryParams(req.query.locale);
if (fromLng) {
req.session.language = fromLng;
} else if (fromLocale) {
req.session.language = fromLocale;
}
}
next();
};

module.exports = setLanguageForSession;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"get-port": "^4.2.0",
"git-rev-sync": "^3.0.2",
"govuk-frontend": "^4.9.0",
"helmet": "^3.23.3",
"helmet": "^8.0.0",
"hpkp": "^3.0.0",
"http-terminator": "^3.0.0",
"https-proxy-agent": "^5.0.1",
Expand Down
40 changes: 40 additions & 0 deletions test/component/testHelmet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict';

const {assert} = require('chai');
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const express = require('express');
const helmet = require('helmet');

const app = proxyquire('app', {
'express': express,
'helmet': helmet,
});

describe('app-config-helmet', () => {
it('should use helmet.strictTransportSecurity with appropriate maxAge', (done) => {
const stsSpy = sinon.spy(helmet, 'strictTransportSecurity');

const server = app.init();
server.http.close();

stsSpy.restore();

const expectedMinimumMaxAge = 31536000;
const seenAges = [];

assert(
stsSpy.calledWith(
sinon.match.has('maxAge', sinon.match((val) => {
seenAges.push(val);
return val >= expectedMinimumMaxAge;
}))),
`strictTransportSecurity not called with maxAge >= ${expectedMinimumMaxAge}, saw ${seenAges.join()}`);

const called = stsSpy.callCount;
assert.equal(called, 1,
`Expected strictTransportSecurity to be called once but was called ${called} times`);

done();
});
});
111 changes: 111 additions & 0 deletions test/unit/middleware/testSetSessionLanguage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'use strict';

const setSessionLanguage = require('../../../app/middleware/setSessionLanguage');

const {assert} = require('chai');
const sinon = require('sinon');

describe('SetSessionLanguage', () => {
let req;
let res;
let next;

const preset = {'preset': null};
const en = 'en';
const cy = 'cy';
// we do not support french
const invalid = 'fr';

beforeEach(() => {
res = {};
req = {
session: {
language: null,
},
query: null,
};
next = sinon.spy();
});

describe('setSessionLanguage()', () => {

it('should default session lang to en if no value is set in the request or the query', () => {
setSessionLanguage(req, res, next);
assert.equal(req.session.language, en);
});

it('should leave session lang set if no value in the query', () => {
req.session.language = preset;
setSessionLanguage(req, res, next);
assert.equal(req.session.language, preset);
});

it('should not override session lang if query lng value invalid', () => {
req.session.language = preset;
req.query = {lng: invalid};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, preset);
});

it('should not override session lang if query lng array all invalid', () => {
req.session.language = preset;
req.query = {lng: [invalid, invalid]};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, preset);
});

it('should override session lang to valid query lng value', () => {
req.session.language = preset;
req.query = {lng: cy};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, cy);
});

it('should override session lang to first valid query lng array value', () => {
req.session.language = preset;
req.query = {lng: [invalid, cy]};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, cy);
});

//

it('should not override session lang if query locale value invalid', () => {
req.session.language = preset;
req.query = {locale: invalid};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, preset);
});

it('should not override session lang if query locale array all invalid', () => {
req.session.language = preset;
req.query = {locale: [invalid, invalid]};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, preset);
});

it('should override session lang to valid query locale value', () => {
req.session.language = preset;
req.query = {locale: cy};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, cy);
});

it('should override session lang to first valid query locale array value', () => {
req.session.language = preset;
req.query = {locale: [invalid, cy]};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, cy);
});

it('should use query lng value rather than query locale value', () => {
req.session.language = preset;
req.query = {
lng: en,
locale: cy,
};
setSessionLanguage(req, res, next);
assert.equal(req.session.language, en);
});
});
});
2 changes: 1 addition & 1 deletion yarn-audit-known-issues
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
{"value":"rimraf","children":{"ID":"rimraf (deprecation)","Issue":"Rimraf versions prior to v4 are no longer supported","Severity":"moderate","Vulnerable Versions":"2.7.1","Tree Versions":["2.7.1"],"Dependents":["fstream@npm:1.0.12"]}}
{"value":"tough-cookie","children":{"ID":1097682,"Issue":"tough-cookie Prototype Pollution vulnerability","URL":"https://github.com/advisories/GHSA-72xf-g2v4-qvf3","Severity":"moderate","Vulnerable Versions":"<4.1.3","Tree Versions":["2.5.0"],"Dependents":["request@npm:2.88.2"]}}
{"value":"uuid","children":{"ID":"uuid (deprecation)","Issue":"Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.","Severity":"moderate","Vulnerable Versions":"3.4.0","Tree Versions":["3.4.0"],"Dependents":["request@npm:2.88.2"]}}
{"value":"ws","children":{"ID":1098392,"Issue":"ws affected by a DoS when handling a request with many HTTP headers","URL":"https://github.com/advisories/GHSA-3h5v-q93c-6h6q","Severity":"high","Vulnerable Versions":">=8.0.0 <8.17.1","Tree Versions":["8.13.0"],"Dependents":["puppeteer-core@virtual:9c3ab89bc6ffaa83ae7ee58d9f1b7b4ced81beaf168bd0f17e701a7eb3b1f1cebbfa39b9ec96184d21605ed14a2d9090c02ee4d77744445e46cebef8b5b4dc83#npm:20.9.0"]}}
{"value":"ws","children":{"ID":1098392,"Issue":"ws affected by a DoS when handling a request with many HTTP headers","URL":"https://github.com/advisories/GHSA-3h5v-q93c-6h6q","Severity":"high","Vulnerable Versions":">=8.0.0 <8.17.1","Tree Versions":["8.13.0"],"Dependents":["puppeteer-core@npm:21.11.0", "puppeteer-core@virtual:337caec2a3c4a9d98980f7a6edb1a88914aacf82463dd61584cb9802a17c747ed9548326469043cf91fccce15e72b10937248a8f7cba2ca22089a5d6a027ad74#npm:20.9.0"]}}
Loading