hof 20.0.0-redis-beta.32-redis-beta → 20.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.github/workflows/automate-publish.yml +1 -1
  2. package/.github/workflows/automate-tag.yml +4 -4
  3. package/README.md +6 -0
  4. package/components/notify/notify.js +1 -1
  5. package/config/hof-defaults.js +1 -2
  6. package/config/sanitisation-rules.js +20 -17
  7. package/controller/base-controller.js +5 -3
  8. package/controller/controller.js +5 -0
  9. package/frontend/template-partials/views/layout.html +2 -2
  10. package/frontend/template-partials/views/partials/maincontent-left.html +2 -2
  11. package/frontend/template-partials/views/partials/navigation.html +2 -2
  12. package/frontend/template-partials/views/partials/summary-table-row.html +2 -2
  13. package/frontend/template-partials/views/session-timeout.html +2 -1
  14. package/index.js +1 -1
  15. package/lib/health.js +1 -1
  16. package/lib/sessions.js +1 -1
  17. package/middleware/errors.js +2 -0
  18. package/middleware/rate-limiter.js +1 -3
  19. package/package.json +5 -4
  20. package/sandbox/server.js +1 -1
  21. package/wizard/middleware/check-progress.js +36 -1
  22. package/.nyc_output/cb764db8-e9f0-43bb-b3b1-7af57bb79bb5.json +0 -1
  23. package/.nyc_output/processinfo/cb764db8-e9f0-43bb-b3b1-7af57bb79bb5.json +0 -1
  24. package/.nyc_output/processinfo/index.json +0 -1
  25. package/sandbox/apps/sandbox/translations/en/default.json +0 -224
  26. package/sandbox/public/css/app.css +0 -2794
  27. package/sandbox/public/images/icons/icon-caret-left.png +0 -0
  28. package/sandbox/public/images/icons/icon-complete.png +0 -0
  29. package/sandbox/public/images/icons/icon-cross-remove-sign.png +0 -0
  30. package/sandbox/public/js/bundle.js +0 -32888
@@ -16,7 +16,7 @@ jobs:
16
16
  fetch-depth: 0
17
17
  - uses: actions/setup-node@v1
18
18
  with:
19
- node-version: 14
19
+ node-version: 10
20
20
  registry-url: https://registry.npmjs.org/
21
21
  - name: 'Get Previous tag'
22
22
  id: previoustag
@@ -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: 14
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: 14
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: 14
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 '/'.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  const NotifyClient = require('notifications-node-client').NotifyClient;
3
- const {v4: uuidv4} = require('uuid');
3
+ const { v4: uuidv4 } = require('uuid');
4
4
 
5
5
  module.exports = class Notify {
6
6
  constructor(opts) {
@@ -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
- const regexQuery = new RegExp(blacklistedDetail.regex, 'gi');
181
- // Will perform the required replace based on our passed in regex and the replace string
182
- req.form.values[property] = req.form.values[property].replace(regexQuery, blacklistedDetail.replace);
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
  });
@@ -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-xl">{{header}}</h1>{{/header}}
7
- {{#subHeading}}<div id="page-header" class="govuk-heading-l">{{subHeading}}</div>{{/subHeading}}
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="{{baseUrl}}" class="govuk-header__link govuk-header__link--service-name" id="proposition-name">{{$journeyHeader}}{{/journeyHeader}}</a>
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"><a href="{{changeLink}}" id="{{field}}-change-{{index}}">{{#t}}buttons.change{{/t}} <span class="visuallyhidden">{{changeLinkDescription}} from {{value}}</span></a></span></dd>
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"><a href="{{baseUrl}}{{step}}/edit#{{field}}" id="{{field}}-change">{{#t}}buttons.change{{/t}} <span class="visuallyhidden">{{changeLinkDescription}} from {{value}}</span></a></span></dd>
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
- <p>{{{content.message}}}</p>
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
@@ -15,7 +15,7 @@ module.exports = redis => {
15
15
 
16
16
  router.get('/readiness', healthCheck({
17
17
  test: () => {
18
- if (!redis.isOpen && !redis.isReady) {
18
+ if (!redis.connected && !redis.ready) {
19
19
  return new Error('Session store unhealthy');
20
20
  }
21
21
  return 0;
package/lib/sessions.js CHANGED
@@ -50,7 +50,7 @@ module.exports = (app, config) => {
50
50
  logger.error(e);
51
51
  });
52
52
  }
53
- client.connect();
53
+
54
54
  const store = new RedisStore({
55
55
  client: client,
56
56
  ttl: config.session.ttl,
@@ -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.v4.QUIT();
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.0-redis-beta.32-redis-beta",
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": "^6.1.3",
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.2",
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": "^4.3.1",
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
@@ -14,5 +14,5 @@ bootstrap({
14
14
  }
15
15
  },
16
16
  getAccessibility: true,
17
- "port": 8080
17
+ "port": 8082
18
18
  });
@@ -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] : getAllPossibleSteps(nextStep, steps);
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