hof 20.0.0-redis-beta.32-redis-beta → 20.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/.github/workflows/automate-publish.yml +1 -1
- package/.github/workflows/automate-tag.yml +4 -4
- package/README.md +6 -0
- package/components/notify/notify.js +1 -1
- package/config/hof-defaults.js +1 -2
- package/config/sanitisation-rules.js +20 -17
- package/controller/base-controller.js +5 -3
- package/controller/controller.js +5 -0
- package/frontend/template-partials/views/layout.html +2 -2
- package/frontend/template-partials/views/partials/maincontent-left.html +2 -2
- package/frontend/template-partials/views/partials/navigation.html +2 -2
- package/frontend/template-partials/views/partials/summary-table-row.html +2 -2
- package/frontend/template-partials/views/session-timeout.html +2 -1
- package/index.js +1 -1
- package/lib/health.js +1 -1
- package/lib/sessions.js +1 -1
- package/middleware/errors.js +2 -0
- package/middleware/rate-limiter.js +1 -3
- package/package.json +5 -4
- package/sandbox/server.js +1 -1
- package/wizard/middleware/check-progress.js +36 -1
- package/.nyc_output/cb764db8-e9f0-43bb-b3b1-7af57bb79bb5.json +0 -1
- package/.nyc_output/processinfo/cb764db8-e9f0-43bb-b3b1-7af57bb79bb5.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/sandbox/apps/sandbox/translations/en/default.json +0 -224
- package/sandbox/public/css/app.css +0 -2794
- package/sandbox/public/images/icons/icon-caret-left.png +0 -0
- package/sandbox/public/images/icons/icon-complete.png +0 -0
- package/sandbox/public/images/icons/icon-cross-remove-sign.png +0 -0
- package/sandbox/public/js/bundle.js +0 -32888
@@ -7,7 +7,7 @@ jobs:
|
|
7
7
|
runs-on: ubuntu-latest
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
node-version: [14.x]
|
10
|
+
node-version: [10.x, 12.x, 14.x]
|
11
11
|
redis-version: [4, 5, 6]
|
12
12
|
steps:
|
13
13
|
- uses: actions/checkout@v2.2.0
|
@@ -34,7 +34,7 @@ jobs:
|
|
34
34
|
- uses: actions/checkout@v2.2.0
|
35
35
|
- uses: actions/setup-node@v1
|
36
36
|
with:
|
37
|
-
node-version:
|
37
|
+
node-version: 10
|
38
38
|
registry-url: https://registry.npmjs.org/
|
39
39
|
- run: |
|
40
40
|
git config --local user.email "$(git log --format='%ae' HEAD^!)"
|
@@ -52,7 +52,7 @@ jobs:
|
|
52
52
|
- uses: actions/checkout@v2.2.0
|
53
53
|
- uses: actions/setup-node@v1
|
54
54
|
with:
|
55
|
-
node-version:
|
55
|
+
node-version: 10
|
56
56
|
registry-url: https://registry.npmjs.org/
|
57
57
|
- run: |
|
58
58
|
git config --local user.email "$(git log --format='%ae' HEAD^!)"
|
@@ -70,7 +70,7 @@ jobs:
|
|
70
70
|
- uses: actions/checkout@v2.2.0
|
71
71
|
- uses: actions/setup-node@v1
|
72
72
|
with:
|
73
|
-
node-version:
|
73
|
+
node-version: 10
|
74
74
|
registry-url: https://registry.npmjs.org/
|
75
75
|
- run: |
|
76
76
|
git config --local user.email "$(git log --format='%ae' HEAD^!)"
|
package/README.md
CHANGED
@@ -1722,3 +1722,9 @@ Additional vendor JavaScript files are included. These are:
|
|
1722
1722
|
- safari-cachebuster.js
|
1723
1723
|
|
1724
1724
|
Copy `assets/javascript/vendor` into your javascript directory (ie `hmpo/vendor`) and compile them with your JavaScript.
|
1725
|
+
|
1726
|
+
## Journey Header Navigation.html page
|
1727
|
+
|
1728
|
+
- Navigation.html contains a journeyHeaderURL, which is set in the controller.
|
1729
|
+
- getJourneyHeaderURL within the controller translates an empty baseURL to '/'.
|
1730
|
+
- The above helps fix broken journey header URLs in the GRO and UKVIC services which both have a baseURL's set to '/'.
|
package/config/hof-defaults.js
CHANGED
@@ -27,8 +27,7 @@ const defaults = {
|
|
27
27
|
ignoreMiddlewareLogs: ['/healthz'],
|
28
28
|
redis: {
|
29
29
|
port: process.env.REDIS_PORT || '6379',
|
30
|
-
host: process.env.REDIS_HOST || '127.0.0.1'
|
31
|
-
legacyMode: true
|
30
|
+
host: process.env.REDIS_HOST || '127.0.0.1'
|
32
31
|
},
|
33
32
|
session: {
|
34
33
|
ttl: process.env.SESSION_TTL || 1800,
|
@@ -3,27 +3,30 @@
|
|
3
3
|
|
4
4
|
const sanitisationBlacklistArray = {
|
5
5
|
// Input will be sanitised using the below rules
|
6
|
+
// Each one is an array which will run sequentially
|
7
|
+
// Some have multiple steps which allow us to remove dups then append the suffix
|
8
|
+
// Useful for ensuring we're not re-sanitising the same input multiple times (and appending extra hypens each time)
|
6
9
|
// The key is what we're sanitising out
|
7
10
|
// The regex is the rule we used to find them (note some dictate repeating characters)
|
8
11
|
// And the replace is what we're replacing that pattern with. Usually nothing sometimes a
|
9
12
|
// single character or sometimes a single character followed by a "-"
|
10
|
-
'/*': { regex: '\/\\*', replace: '-' },
|
11
|
-
'*/': { regex: '\\*\\/', replace: '-' },
|
12
|
-
'|': { regex: '\\|', replace: '-' },
|
13
|
-
'&&': { regex: '&&+', replace: '&' },
|
14
|
-
'@@': { regex: '@@+', replace: '@' },
|
15
|
-
'/..;/': { regex: '/\\.\\.;/', replace: '-' }, // Purposely input before ".." as they conflict
|
16
|
-
// '..': { regex: '\\.\\.+', replace: '.' }, // Agreed to disable this rule for now unless its specifically required
|
17
|
-
'/etc/passwd': { regex: '\/etc\/passwd', replace: '-' },
|
18
|
-
'c:\\': { regex: 'c:\\\\', replace: '-' },
|
19
|
-
'cmd.exe': { regex: 'cmd\\.exe', replace: '-' },
|
20
|
-
'<': { regex: '<', replace: '<-' },
|
21
|
-
'>': { regex: '>', replace: '>-' },
|
22
|
-
'[': { regex: '\\[+', replace: '[-' },
|
23
|
-
']': { regex: '\\]+', replace: ']-' },
|
24
|
-
'~': { regex: '~', replace: '~-' },
|
25
|
-
'&#': { regex: '&#', replace: '-' },
|
26
|
-
'%U': { regex: '%U', replace: '-' }
|
13
|
+
'/*': [{ regex: '\/\\*', replace: '-' }],
|
14
|
+
'*/': [{ regex: '\\*\\/', replace: '-' }],
|
15
|
+
'|': [{ regex: '\\|', replace: '-' }],
|
16
|
+
'&&': [{ regex: '&&+', replace: '&' }],
|
17
|
+
'@@': [{ regex: '@@+', replace: '@' }],
|
18
|
+
'/..;/': [{ regex: '/\\.\\.;/', replace: '-' }], // Purposely input before ".." as they conflict
|
19
|
+
// '..': [{ regex: '\\.\\.+', replace: '.' }], // Agreed to disable this rule for now unless its specifically required
|
20
|
+
'/etc/passwd': [{ regex: '\/etc\/passwd', replace: '-' }],
|
21
|
+
'c:\\': [{ regex: 'c:\\\\', replace: '-' }],
|
22
|
+
'cmd.exe': [{ regex: 'cmd\\.exe', replace: '-' }],
|
23
|
+
'<': [{ regex: '<+', replace: '<' }, { regex: '<(?!-)', replace: '<-' }],
|
24
|
+
'>': [{ regex: '>+', replace: '>' }, { regex: '>(?!-)', replace: '>-' }],
|
25
|
+
'[': [{ regex: '\\[+', replace: '[' }, { regex: '\\[(?!-)', replace: '[-' }],
|
26
|
+
']': [{ regex: '\\]+', replace: ']-' }, { regex: '\\](?!-)', replace: ']-' }],
|
27
|
+
'~': [{ regex: '~+', replace: '~' }, { regex: '~(?!-)', replace: '~-' }],
|
28
|
+
'&#': [{ regex: '&#', replace: '-' }],
|
29
|
+
'%U': [{ regex: '%U', replace: '-' }]
|
27
30
|
};
|
28
31
|
|
29
32
|
module.exports = sanitisationBlacklistArray;
|
@@ -177,9 +177,11 @@ module.exports = class BaseController extends EventEmitter {
|
|
177
177
|
// For each property in our form data
|
178
178
|
Object.keys(sanitisationBlacklistArray).forEach(function (blacklisted, blacklistedIndex) {
|
179
179
|
const blacklistedDetail = sanitisationBlacklistArray[blacklisted];
|
180
|
-
|
181
|
-
|
182
|
-
|
180
|
+
blacklistedDetail.forEach(step => {
|
181
|
+
const regexQuery = new RegExp(step.regex, 'gi');
|
182
|
+
// Will perform the required replace based on our passed in regex and the replace string
|
183
|
+
req.form.values[property] = req.form.values[property].replace(regexQuery, step.replace);
|
184
|
+
});
|
183
185
|
});
|
184
186
|
}
|
185
187
|
});
|
package/controller/controller.js
CHANGED
@@ -113,6 +113,7 @@ module.exports = class Controller extends BaseController {
|
|
113
113
|
baseUrl: req.baseUrl,
|
114
114
|
skipToMain: this.getFirstFormItem(req.form.options.fields),
|
115
115
|
title: this.getTitle(route, lookup, req.form.options.fields, res.locals),
|
116
|
+
journeyHeaderURL: this.getJourneyHeaderURL(req.baseUrl),
|
116
117
|
header: this.getHeader(route, lookup, res.locals),
|
117
118
|
captionHeading: this.getCaptionHeading(route, lookup, res.locals),
|
118
119
|
warning: this.getWarning(route, lookup, res.locals),
|
@@ -124,6 +125,10 @@ module.exports = class Controller extends BaseController {
|
|
124
125
|
}, stepLocals);
|
125
126
|
}
|
126
127
|
|
128
|
+
getJourneyHeaderURL(url) {
|
129
|
+
return url === '' ? '/' : url;
|
130
|
+
}
|
131
|
+
|
127
132
|
getFirstFormItem(fields) {
|
128
133
|
let firstFieldKey;
|
129
134
|
if (_.size(fields)) {
|
@@ -44,9 +44,9 @@
|
|
44
44
|
{{/gaTagId}}
|
45
45
|
{{/cookieMessage}}
|
46
46
|
{{$footerSupportLinks}}
|
47
|
-
<ul>
|
47
|
+
<ul class="govuk-footer__inline-list">
|
48
48
|
{{#footerSupportLinks}}
|
49
|
-
<li class="govuk-footer__inline-list-item"><a href="{{path}}">{{#t}}{{property}}{{/t}}</a></li>
|
49
|
+
<li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="{{path}}">{{#t}}{{property}}{{/t}}</a></li>
|
50
50
|
{{/footerSupportLinks}}
|
51
51
|
{{^footerSupportLinks}}
|
52
52
|
<li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/cookies">{{#t}}base.cookies{{/t}}</a></li>
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<div class="govuk-grid-column-two-thirds">
|
4
4
|
{{$validationSummary}}{{/validationSummary}}
|
5
5
|
{{#captionHeading}}<span class="govuk-caption-l">{{captionHeading}}</span>{{/captionHeading}}
|
6
|
-
{{#header}}<h1 class="govuk-heading-
|
7
|
-
{{#subHeading}}<div id="page-header" class="govuk-heading-
|
6
|
+
{{#header}}<h1 class="govuk-heading-l">{{header}}</h1>{{/header}}
|
7
|
+
{{#subHeading}}<div id="page-header"><h2 class="govuk-heading-m">{{subHeading}}</h2></div>{{/subHeading}}
|
8
8
|
{{$content}}{{/content}}
|
9
9
|
</div>
|
10
10
|
{{/content-outer}}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
<div class="govuk-header__content">
|
2
2
|
{{#startPageRedirectUrl}}
|
3
|
-
<a href="{{startPageRedirectUrl}}" class="govuk-header__link govuk-header__link--service-name" id="proposition-name">{{$journeyHeader}}{{/journeyHeader}}</a>
|
3
|
+
<a href="{{startPageRedirectUrl}}" class="govuk-header__link govuk-header__link--service-name" id="proposition-name">{{$journeyHeader}}{{/journeyHeader}}</a>
|
4
4
|
{{/startPageRedirectUrl}}
|
5
5
|
{{^startPageRedirectUrl}}
|
6
|
-
<a href="{{
|
6
|
+
<a href="{{journeyHeaderURL}}" class="govuk-header__link govuk-header__link--service-name" id="proposition-name">{{$journeyHeader}}{{/journeyHeader}}</a>
|
7
7
|
{{/startPageRedirectUrl}}
|
8
8
|
</div>
|
@@ -5,10 +5,10 @@
|
|
5
5
|
<dt class="confirm-label">{{label}}</dt>
|
6
6
|
<dd class="confirm-value" data-value="{{value}}">{{value}}</dd>
|
7
7
|
{{#changeLink}}
|
8
|
-
<dd><span class="link"
|
8
|
+
<dd><span><a class="govuk-link" href="{{changeLink}}" id="{{field}}-change-{{index}}">{{#t}}buttons.change{{/t}} <span class="visuallyhidden">{{changeLinkDescription}} from {{value}}</span></a></span></dd>
|
9
9
|
{{/changeLink}}
|
10
10
|
{{^changeLink}}
|
11
|
-
<dd><span class="link"
|
11
|
+
<dd><span><a class="govuk-link" href="{{baseUrl}}{{step}}/edit#{{field}}" id="{{field}}-change">{{#t}}buttons.change{{/t}} <span class="visuallyhidden">{{changeLinkDescription}} from {{value}}</span></a></span></dd>
|
12
12
|
{{/changeLink}}
|
13
13
|
{{/isSeparator}}
|
14
14
|
</div>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
{{<error}}
|
2
2
|
{{$content}}
|
3
|
-
<
|
3
|
+
<h1 class="govuk-heading-l">{{{content.title}}}</h1>
|
4
|
+
<h2 class="govuk-heading-m">{{{content.message}}}</h2>
|
4
5
|
<a href="{{startLink}}" class="govuk-button" role="button">{{#t}}buttons.start-again{{/t}}</a>
|
5
6
|
{{/content}}
|
6
7
|
{{/error}}
|
package/index.js
CHANGED
@@ -79,7 +79,7 @@ const getContentSecurityPolicy = (config, res) => {
|
|
79
79
|
fontSrc: ['fonts.gstatic.com '],
|
80
80
|
scriptSrc: ['www.google-analytics.com', 'ssl.google-analytics.com'],
|
81
81
|
imgSrc: ['www.google-analytics.com', 'ssl.gstatic.com'],
|
82
|
-
connectSrc: ['www.google-analytics.com']
|
82
|
+
connectSrc: ['https://www.google-analytics.com', 'https://region1.google-analytics.com']
|
83
83
|
};
|
84
84
|
|
85
85
|
if (config.gaTagId) {
|
package/lib/health.js
CHANGED
package/lib/sessions.js
CHANGED
package/middleware/errors.js
CHANGED
@@ -12,6 +12,8 @@ const getContent = (err, translate) => {
|
|
12
12
|
if (err.code === 'SESSION_TIMEOUT') {
|
13
13
|
err.status = 401;
|
14
14
|
err.template = 'session-timeout';
|
15
|
+
err.title = (translate && translate('errors.session.title'));
|
16
|
+
err.message = (translate && translate('errors.session.message'));
|
15
17
|
content.title = (translate && translate('errors.session.title'));
|
16
18
|
content.message = (translate && translate('errors.session.message'));
|
17
19
|
}
|
@@ -25,11 +25,9 @@ module.exports = (options, rateLimitType) => {
|
|
25
25
|
}
|
26
26
|
|
27
27
|
const closeConnection = async err => {
|
28
|
-
await redisClient.
|
28
|
+
await redisClient.quit();
|
29
29
|
return next(err);
|
30
30
|
};
|
31
|
-
redisClient.on('error', err => logger.log('error', err));
|
32
|
-
await redisClient.connect();
|
33
31
|
|
34
32
|
try {
|
35
33
|
// fetch records of current user using IP address, returns null when no record is found
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "hof",
|
3
3
|
"description": "A bootstrap for HOF projects",
|
4
|
-
"version": "20.0.
|
4
|
+
"version": "20.0.1",
|
5
5
|
"license": "MIT",
|
6
6
|
"main": "index.js",
|
7
7
|
"author": "HomeOffice",
|
@@ -42,7 +42,7 @@
|
|
42
42
|
"callsite": "^1.0.0",
|
43
43
|
"chalk": "^2.0.0",
|
44
44
|
"chokidar": "^3.4.0",
|
45
|
-
"connect-redis": "^
|
45
|
+
"connect-redis": "^5.2.0",
|
46
46
|
"cookie-parser": "^1.4.6",
|
47
47
|
"cp": "^0.2.0",
|
48
48
|
"csrf": "^3.0.2",
|
@@ -72,7 +72,7 @@
|
|
72
72
|
"minimatch": "^3.0.3",
|
73
73
|
"minimist": "^1.2.6",
|
74
74
|
"mixwith": "^0.1.1",
|
75
|
-
"moment": "^2.29.
|
75
|
+
"moment": "^2.29.4",
|
76
76
|
"morgan": "^1.10.0",
|
77
77
|
"mustache": "^2.3.0",
|
78
78
|
"nodemailer": "^6.6.3",
|
@@ -80,7 +80,7 @@
|
|
80
80
|
"nodemailer-smtp-transport": "^2.7.4",
|
81
81
|
"nodemailer-stub-transport": "^1.1.0",
|
82
82
|
"notifications-node-client": "^5.1.1",
|
83
|
-
"redis": "^
|
83
|
+
"redis": "^3.1.2",
|
84
84
|
"reqres": "^3.0.1",
|
85
85
|
"request": "^2.79.0",
|
86
86
|
"rimraf": "^3.0.2",
|
@@ -89,6 +89,7 @@
|
|
89
89
|
"uglify-js": "^3.14.3",
|
90
90
|
"underscore": "^1.12.1",
|
91
91
|
"urijs": "^1.19.11",
|
92
|
+
"uuid": "^8.3.2",
|
92
93
|
"winston": "^3.7.2"
|
93
94
|
},
|
94
95
|
"devDependencies": {
|
package/sandbox/server.js
CHANGED
@@ -28,6 +28,41 @@ module.exports = (route, controller, steps, begin) => {
|
|
28
28
|
return _.uniq(allSteps);
|
29
29
|
};
|
30
30
|
|
31
|
+
// Gets all the possible routes
|
32
|
+
const walkAllPossibleSteps = (stepName, allStepsInService, allVisitedSteps) => {
|
33
|
+
const stepIncludingFieldsAndForks = allStepsInService[stepName];
|
34
|
+
if (!stepIncludingFieldsAndForks) { return; }
|
35
|
+
|
36
|
+
const forkTargets = _.map(stepIncludingFieldsAndForks.forks, 'target') || [];
|
37
|
+
const nextStep = stepIncludingFieldsAndForks.next || '';
|
38
|
+
|
39
|
+
// If there is no next step or fork, then we have reached the end of the journey
|
40
|
+
if (!forkTargets.length && !nextStep) {
|
41
|
+
allVisitedSteps.push(stepName);
|
42
|
+
// eslint-disable-next-line consistent-return
|
43
|
+
return _.uniq(allVisitedSteps);
|
44
|
+
}
|
45
|
+
|
46
|
+
const nextStepsAndForks = _.uniq(forkTargets.concat(nextStep));
|
47
|
+
|
48
|
+
// We need to transverse through all 'Next' and 'Forks' for this route
|
49
|
+
nextStepsAndForks.map(each => {
|
50
|
+
if (!allVisitedSteps.includes(each)) {
|
51
|
+
allVisitedSteps.push(each);
|
52
|
+
walkAllPossibleSteps(each, allStepsInService, allVisitedSteps);
|
53
|
+
}
|
54
|
+
});
|
55
|
+
};
|
56
|
+
|
57
|
+
// Create a list of all visited steps
|
58
|
+
const createAllVisitedSteps = (stepName, allStepsInService) => {
|
59
|
+
const allVisitedSteps = [stepName];
|
60
|
+
if (allStepsInService[stepName]) {
|
61
|
+
walkAllPossibleSteps(stepName, allStepsInService, allVisitedSteps);
|
62
|
+
}
|
63
|
+
return _.uniq(allVisitedSteps);
|
64
|
+
};
|
65
|
+
|
31
66
|
const invalidateStep = (stepName, scopedSteps, sessionModel) => {
|
32
67
|
debug('Invalidating', stepName);
|
33
68
|
const step = scopedSteps[stepName] || {};
|
@@ -55,7 +90,7 @@ module.exports = (route, controller, steps, begin) => {
|
|
55
90
|
debug('next', nextStep);
|
56
91
|
debug('potential paths', potentialPaths);
|
57
92
|
// if we're following a loop then allow the loop to be invalidated
|
58
|
-
const whitelist = isLoop(nextStep, req.path) ? [route] :
|
93
|
+
const whitelist = isLoop(nextStep, req.path) ? [route] : createAllVisitedSteps(nextStep, steps);
|
59
94
|
// aggregate all potential journeys from the invalidating step
|
60
95
|
const invalidateSteps = potentialPaths.reduce((arr, step) => arr.concat(getAllPossibleSteps(step, steps)), []);
|
61
96
|
|