@dwp/govuk-casa 8.3.0 → 8.5.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.
- package/CHANGELOG.md +16 -0
- package/dist/assets/css/casa-ie8.css +1 -1
- package/dist/assets/css/casa.css +1 -1
- package/dist/lib/field.d.ts +6 -0
- package/dist/lib/field.js +29 -1
- package/dist/lib/nunjucks-filters.d.ts +15 -3
- package/dist/lib/nunjucks-filters.js +9 -4
- package/dist/lib/waypoint-url.d.ts +9 -0
- package/dist/lib/waypoint-url.js +9 -0
- package/dist/middleware/post.js +6 -6
- package/dist/middleware/pre.js +7 -6
- package/dist/middleware/steer-journey.js +7 -1
- package/package.json +23 -23
package/dist/lib/field.js
CHANGED
|
@@ -18,7 +18,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
18
18
|
exports.PageField = void 0;
|
|
19
19
|
const lodash_1 = __importDefault(require("lodash"));
|
|
20
20
|
const utils_js_1 = require("./utils.js");
|
|
21
|
+
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
21
22
|
const { isFunction } = lodash_1.default;
|
|
23
|
+
const log = (0, logger_js_1.default)('lib:field');
|
|
22
24
|
/**
|
|
23
25
|
* @access private
|
|
24
26
|
* @typedef {import('./index').JourneyContext} JourneyContext
|
|
@@ -100,6 +102,27 @@ class PageField {
|
|
|
100
102
|
// Apply name
|
|
101
103
|
this.rename(name);
|
|
102
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Clone this field.
|
|
107
|
+
*
|
|
108
|
+
* @returns {PageField} Cloned field
|
|
109
|
+
*/
|
|
110
|
+
clone() {
|
|
111
|
+
const clone = new PageField(__classPrivateFieldGet(this, _PageField_name, "f"), {
|
|
112
|
+
optional: __classPrivateFieldGet(this, _PageField_meta, "f").optional,
|
|
113
|
+
persist: __classPrivateFieldGet(this, _PageField_meta, "f").persist,
|
|
114
|
+
});
|
|
115
|
+
if (this.validators()) {
|
|
116
|
+
clone.validators(this.validators());
|
|
117
|
+
}
|
|
118
|
+
if (this.conditions()) {
|
|
119
|
+
clone.conditions(this.conditions());
|
|
120
|
+
}
|
|
121
|
+
if (this.processors()) {
|
|
122
|
+
clone.processors(this.processors());
|
|
123
|
+
}
|
|
124
|
+
return clone;
|
|
125
|
+
}
|
|
103
126
|
/**
|
|
104
127
|
* Extract this field's value from the given object.
|
|
105
128
|
*
|
|
@@ -243,7 +266,12 @@ class PageField {
|
|
|
243
266
|
// ESLint disabled as `i` is an integer
|
|
244
267
|
/* eslint-disable security/detect-object-injection */
|
|
245
268
|
// TODO: Replace `value` with `context.fieldValue` here
|
|
246
|
-
|
|
269
|
+
let fieldErrors = __classPrivateFieldGet(this, _PageField_validators, "f")[i].validate(value, context);
|
|
270
|
+
if (!Array.isArray(fieldErrors)) {
|
|
271
|
+
// Friendly message for developer
|
|
272
|
+
throw new TypeError(`The validator at index ${i} (name: ${__classPrivateFieldGet(this, _PageField_validators, "f")[i].name || 'unknown'}) for field '${__classPrivateFieldGet(this, _PageField_name, "f")}' did not return an array`);
|
|
273
|
+
}
|
|
274
|
+
fieldErrors = fieldErrors.map((e) => e.withContext(Object.assign(Object.assign({}, context), { validator: __classPrivateFieldGet(this, _PageField_validators, "f")[i].name })));
|
|
247
275
|
/* eslint-enable security/detect-object-injection */
|
|
248
276
|
errors = [
|
|
249
277
|
...errors,
|
|
@@ -17,11 +17,23 @@ export function includes(source?: any[], search?: any): boolean;
|
|
|
17
17
|
* object - {dd:'', mm:'', yyyy:''}
|
|
18
18
|
*
|
|
19
19
|
* @memberof NunjucksFilters
|
|
20
|
-
* @param {object} date Date
|
|
21
|
-
* @param {
|
|
20
|
+
* @param {object} date Date
|
|
21
|
+
* @param {string} date.dd Day
|
|
22
|
+
* @param {string} date.mm Month
|
|
23
|
+
* @param {string} date.yyyy Year
|
|
24
|
+
* @param {object} [config] Options
|
|
25
|
+
* @param {string} [config.locale] Locale (default 'en')
|
|
26
|
+
* @param {string} [config.format] Format (default 'd MMMM yyyy')
|
|
22
27
|
* @returns {string} Formatted date
|
|
23
28
|
*/
|
|
24
|
-
export function formatDateObject(date:
|
|
29
|
+
export function formatDateObject(date: {
|
|
30
|
+
dd: string;
|
|
31
|
+
mm: string;
|
|
32
|
+
yyyy: string;
|
|
33
|
+
}, config?: {
|
|
34
|
+
locale?: string | undefined;
|
|
35
|
+
format?: string | undefined;
|
|
36
|
+
} | undefined): string;
|
|
25
37
|
/**
|
|
26
38
|
* Attribute values will be HTML/attribute escaped.
|
|
27
39
|
*
|
|
@@ -54,12 +54,17 @@ exports.includes = includes;
|
|
|
54
54
|
* object - {dd:'', mm:'', yyyy:''}
|
|
55
55
|
*
|
|
56
56
|
* @memberof NunjucksFilters
|
|
57
|
-
* @param {object} date Date
|
|
58
|
-
* @param {
|
|
57
|
+
* @param {object} date Date
|
|
58
|
+
* @param {string} date.dd Day
|
|
59
|
+
* @param {string} date.mm Month
|
|
60
|
+
* @param {string} date.yyyy Year
|
|
61
|
+
* @param {object} [config] Options
|
|
62
|
+
* @param {string} [config.locale] Locale (default 'en')
|
|
63
|
+
* @param {string} [config.format] Format (default 'd MMMM yyyy')
|
|
59
64
|
* @returns {string} Formatted date
|
|
60
65
|
*/
|
|
61
66
|
function formatDateObject(date, config = {}) {
|
|
62
|
-
const { locale = 'en' } = config;
|
|
67
|
+
const { locale = 'en', format = 'd MMMM yyyy' } = config;
|
|
63
68
|
if (Object.prototype.toString.call(date) === '[object Object]'
|
|
64
69
|
&& 'yyyy' in date
|
|
65
70
|
&& 'mm' in date
|
|
@@ -68,7 +73,7 @@ function formatDateObject(date, config = {}) {
|
|
|
68
73
|
year: Math.max(0, parseInt(date.yyyy, 10)),
|
|
69
74
|
month: Math.max(0, parseInt(date.mm, 10)),
|
|
70
75
|
day: Math.max(1, parseInt(date.dd, 10)),
|
|
71
|
-
}).setLocale(locale).toFormat(
|
|
76
|
+
}).setLocale(locale).toFormat(format);
|
|
72
77
|
}
|
|
73
78
|
return 'INVALID DATE OBJECT';
|
|
74
79
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generate a URL pointing at a particular waypoint.
|
|
3
3
|
*
|
|
4
|
+
* @example
|
|
5
|
+
* // generates: /path/details?edit&editorigin=%2Fsomewhere%2Felse
|
|
6
|
+
* waypointUrl({
|
|
7
|
+
* mountUrl: '/path/',
|
|
8
|
+
* waypoint: 'details',
|
|
9
|
+
* edit: true,
|
|
10
|
+
* editOrigin: '/somewhere/else'
|
|
11
|
+
* })
|
|
12
|
+
*
|
|
4
13
|
* @memberof module:@dwp/govuk-casa
|
|
5
14
|
* @param {object} obj Options
|
|
6
15
|
* @param {string} obj.waypoint Waypoint
|
package/dist/lib/waypoint-url.js
CHANGED
|
@@ -17,6 +17,15 @@ const sanitiseWaypoint = (w) => w.replace(/[^/a-z0-9_-]/ig, '').replace(/\/+/g,
|
|
|
17
17
|
/**
|
|
18
18
|
* Generate a URL pointing at a particular waypoint.
|
|
19
19
|
*
|
|
20
|
+
* @example
|
|
21
|
+
* // generates: /path/details?edit&editorigin=%2Fsomewhere%2Felse
|
|
22
|
+
* waypointUrl({
|
|
23
|
+
* mountUrl: '/path/',
|
|
24
|
+
* waypoint: 'details',
|
|
25
|
+
* edit: true,
|
|
26
|
+
* editOrigin: '/somewhere/else'
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
20
29
|
* @memberof module:@dwp/govuk-casa
|
|
21
30
|
* @param {object} obj Options
|
|
22
31
|
* @param {string} obj.waypoint Waypoint
|
package/dist/middleware/post.js
CHANGED
|
@@ -26,31 +26,31 @@ function postMiddleware() {
|
|
|
26
26
|
// CSRF token is invalid in some way
|
|
27
27
|
if ((err === null || err === void 0 ? void 0 : err.code) === 'EBADCSRFTOKEN') {
|
|
28
28
|
log.info('CSRF validation has failed. This may be caused by the user submitting a stale form from a previous session [EBADCSRFTOKEN]');
|
|
29
|
-
return res.status(403).render(TEMPLATE, { errorCode: 'bad_csrf_token' });
|
|
29
|
+
return res.status(403).render(TEMPLATE, { errorCode: 'bad_csrf_token', error: err });
|
|
30
30
|
}
|
|
31
31
|
// Body parsing verification check failed
|
|
32
32
|
if ((err === null || err === void 0 ? void 0 : err.type) === 'entity.verify.failed') {
|
|
33
33
|
log.info('Body parser verification has failed. This has been caused by the user submitting a payload containing invalid data [entity.verify.failed]');
|
|
34
|
-
return res.status(403).render(TEMPLATE, { errorCode: 'invalid_payload' });
|
|
34
|
+
return res.status(403).render(TEMPLATE, { errorCode: 'invalid_payload', error: err });
|
|
35
35
|
}
|
|
36
36
|
// Too many parameters submitted
|
|
37
37
|
if ((err === null || err === void 0 ? void 0 : err.type) === 'parameters.too.many') {
|
|
38
38
|
log.info('The request contains more parameters than is currently allowed [parameters.too.many]');
|
|
39
|
-
return res.status(413).render(TEMPLATE, { errorCode: 'parameter_limit_exceeded' });
|
|
39
|
+
return res.status(413).render(TEMPLATE, { errorCode: 'parameter_limit_exceeded', error: err });
|
|
40
40
|
}
|
|
41
41
|
// Overall payload too large
|
|
42
42
|
if ((err === null || err === void 0 ? void 0 : err.type) === 'entity.too.large') {
|
|
43
43
|
log.info(`The request payload is too large. Received ${err.length}b with a maximum of ${err.limit}b [parameters.too.many]`);
|
|
44
|
-
return res.status(413).render(TEMPLATE, { errorCode: 'payload_size_exceeded' });
|
|
44
|
+
return res.status(413).render(TEMPLATE, { errorCode: 'payload_size_exceeded', error: err });
|
|
45
45
|
}
|
|
46
46
|
// Unaccept request method
|
|
47
47
|
if ((err === null || err === void 0 ? void 0 : err.code) === 'unaccepted_request_method') {
|
|
48
48
|
log.info(err.message);
|
|
49
|
-
return res.status(400).render(TEMPLATE, { errorCode: 'unaccepted_request_method' });
|
|
49
|
+
return res.status(400).render(TEMPLATE, { errorCode: 'unaccepted_request_method', error: err });
|
|
50
50
|
}
|
|
51
51
|
// Unknown error
|
|
52
52
|
log.error(`Unknown error: ${err.message}; stacktrace: ${err.stack}`);
|
|
53
|
-
return res.status(200).render(TEMPLATE);
|
|
53
|
+
return res.status(200).render(TEMPLATE, { error: err });
|
|
54
54
|
},
|
|
55
55
|
];
|
|
56
56
|
}
|
package/dist/middleware/pre.js
CHANGED
|
@@ -7,7 +7,8 @@ const crypto_1 = require("crypto");
|
|
|
7
7
|
const helmet_1 = __importDefault(require("helmet"));
|
|
8
8
|
const GA_DOMAIN = '*.google-analytics.com';
|
|
9
9
|
const GA_ANALYTICS_DOMAIN = '*.analytics.google.com';
|
|
10
|
-
const GTM_DOMAIN = '
|
|
10
|
+
const GTM_DOMAIN = '*.googletagmanager.com';
|
|
11
|
+
const GTM_PREVIEW_DOMAIN = 'https://tagmanager.google.com';
|
|
11
12
|
/**
|
|
12
13
|
* @access private
|
|
13
14
|
* @typedef {import('../casa').HelmetConfigurator} HelmetConfigurator
|
|
@@ -55,14 +56,14 @@ exports.default = ({ helmetConfigurator = (config) => (config), } = {}) => [
|
|
|
55
56
|
useDefaults: true,
|
|
56
57
|
directives: {
|
|
57
58
|
'default-src': ["'none'"],
|
|
58
|
-
'script-src': ["'self'", GA_DOMAIN, GTM_DOMAIN, (req, res) => `'nonce-${res.locals.cspNonce}'`],
|
|
59
|
-
'img-src': ["'self'", GA_DOMAIN, GA_ANALYTICS_DOMAIN],
|
|
60
|
-
'connect-src': ["'self'", GA_DOMAIN, GA_ANALYTICS_DOMAIN],
|
|
59
|
+
'script-src': ["'self'", GA_DOMAIN, GTM_DOMAIN, GTM_PREVIEW_DOMAIN, (req, res) => `'nonce-${res.locals.cspNonce}'`],
|
|
60
|
+
'img-src': ["'self'", GA_DOMAIN, GA_ANALYTICS_DOMAIN, GTM_DOMAIN, 'https://ssl.gstatic.com', 'https://www.gstatic.com'],
|
|
61
|
+
'connect-src': ["'self'", GA_DOMAIN, GA_ANALYTICS_DOMAIN, GTM_DOMAIN],
|
|
61
62
|
'frame-src': ["'self'", GTM_DOMAIN],
|
|
62
63
|
'frame-ancestors': ["'self'"],
|
|
63
64
|
'form-action': ["'self'"],
|
|
64
|
-
'style-src': ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
|
|
65
|
-
'font-src': ["'self'"],
|
|
65
|
+
'style-src': ["'self'", 'https://fonts.googleapis.com', GTM_PREVIEW_DOMAIN, (req, res) => `'nonce-${res.locals.cspNonce}'`],
|
|
66
|
+
'font-src': ["'self'", 'data:', 'https://fonts.gstatic.com'],
|
|
66
67
|
},
|
|
67
68
|
},
|
|
68
69
|
// // Require referrer to aid navigation
|
|
@@ -57,7 +57,13 @@ exports.default = ({ waypoint, plan, }) => [
|
|
|
57
57
|
startWaypoint: waypoint,
|
|
58
58
|
stopCondition: () => (true), // stop at the first one
|
|
59
59
|
});
|
|
60
|
-
res.locals.casa.journeyPreviousUrl = prevRoute.target ? (0, waypoint_url_js_1.default)({
|
|
60
|
+
res.locals.casa.journeyPreviousUrl = prevRoute.target ? (0, waypoint_url_js_1.default)({
|
|
61
|
+
mountUrl,
|
|
62
|
+
waypoint: prevRoute.target,
|
|
63
|
+
routeName: 'prev',
|
|
64
|
+
edit: req.casa.editMode,
|
|
65
|
+
editOrigin: req.casa.editOrigin,
|
|
66
|
+
}) : undefined;
|
|
61
67
|
return next();
|
|
62
68
|
},
|
|
63
69
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwp/govuk-casa",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.1",
|
|
4
4
|
"description": "A framework for building GOVUK Collect-And-Submit-Applications",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -46,54 +46,54 @@
|
|
|
46
46
|
"csurf": "1.11.0",
|
|
47
47
|
"debug": "4.3.4",
|
|
48
48
|
"deepmerge": "4.2.2",
|
|
49
|
-
"express": "4.18.
|
|
49
|
+
"express": "4.18.2",
|
|
50
50
|
"express-session": "1.17.3",
|
|
51
|
-
"govuk-frontend": "4.
|
|
51
|
+
"govuk-frontend": "4.3.1",
|
|
52
52
|
"graphlib": "2.1.8",
|
|
53
|
-
"helmet": "5.1.
|
|
54
|
-
"i18next": "21.
|
|
53
|
+
"helmet": "5.1.1",
|
|
54
|
+
"i18next": "21.10.0",
|
|
55
55
|
"i18next-http-middleware": "3.2.1",
|
|
56
56
|
"js-yaml": "4.1.0",
|
|
57
57
|
"lodash": "4.17.21",
|
|
58
|
-
"luxon": "2.
|
|
58
|
+
"luxon": "2.5.0",
|
|
59
59
|
"nunjucks": "3.2.3",
|
|
60
60
|
"path-to-regexp": "6.2.1",
|
|
61
61
|
"uuid": "8.3.2",
|
|
62
62
|
"validator": "13.7.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@babel/core": "7.
|
|
66
|
-
"@babel/eslint-parser": "7.
|
|
67
|
-
"@babel/preset-env": "7.
|
|
68
|
-
"@ckeditor/jsdoc-plugins": "30.
|
|
69
|
-
"@commitlint/config-conventional": "17.0
|
|
70
|
-
"@dwp/casa-spiderplan": "2.4.
|
|
65
|
+
"@babel/core": "7.19.3",
|
|
66
|
+
"@babel/eslint-parser": "7.19.1",
|
|
67
|
+
"@babel/preset-env": "7.19.4",
|
|
68
|
+
"@ckeditor/jsdoc-plugins": "30.5.0",
|
|
69
|
+
"@commitlint/config-conventional": "17.1.0",
|
|
70
|
+
"@dwp/casa-spiderplan": "2.4.1",
|
|
71
71
|
"@dwp/casa-spiderplan-a11y-plugin": "0.1.4",
|
|
72
72
|
"@dwp/casa-spiderplan-zap-plugin": "0.1.1",
|
|
73
73
|
"@dwp/eslint-config-base": "6.0.0",
|
|
74
|
-
"@types/express": "4.17.
|
|
74
|
+
"@types/express": "4.17.14",
|
|
75
75
|
"@types/node": "18.0.0",
|
|
76
76
|
"@types/nunjucks": "3.2.1",
|
|
77
77
|
"babel-eslint": "10.1.0",
|
|
78
|
-
"c8": "7.
|
|
78
|
+
"c8": "7.12.0",
|
|
79
79
|
"chai": "4.3.6",
|
|
80
80
|
"cheerio": "1.0.0-rc.12",
|
|
81
|
-
"commitlint": "17.
|
|
81
|
+
"commitlint": "17.1.2",
|
|
82
82
|
"docdash": "1.2.0",
|
|
83
|
-
"eslint": "8.
|
|
83
|
+
"eslint": "8.25.0",
|
|
84
84
|
"eslint-plugin-no-unsafe-regex": "1.0.0",
|
|
85
85
|
"eslint-plugin-security": "1.5.0",
|
|
86
|
-
"eslint-plugin-sonarjs": "0.
|
|
87
|
-
"fast-check": "3.0
|
|
86
|
+
"eslint-plugin-sonarjs": "0.16.0",
|
|
87
|
+
"fast-check": "3.2.0",
|
|
88
88
|
"husky": "8.0.1",
|
|
89
|
-
"jsdoc": "3.6.
|
|
89
|
+
"jsdoc": "3.6.11",
|
|
90
90
|
"jsdoc-tsimport-plugin": "1.0.5",
|
|
91
91
|
"mocha": "10.0.0",
|
|
92
|
-
"sass": "1.
|
|
93
|
-
"sinon": "14.0.
|
|
92
|
+
"sass": "1.55.0",
|
|
93
|
+
"sinon": "14.0.1",
|
|
94
94
|
"sinon-chai": "3.7.0",
|
|
95
95
|
"standard-version": "9.5.0",
|
|
96
|
-
"supertest": "6.
|
|
97
|
-
"typescript": "4.
|
|
96
|
+
"supertest": "6.3.0",
|
|
97
|
+
"typescript": "4.8.4"
|
|
98
98
|
}
|
|
99
99
|
}
|