@dwp/govuk-casa 7.0.8 → 7.0.9

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 (100) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/middleware/page/journey-continue.js +5 -0
  3. package/package.json +15 -15
  4. package/dist/assets/css/casa-ie8.css +0 -1
  5. package/dist/assets/css/casa.css +0 -1
  6. package/dist/casa.d.ts +0 -11
  7. package/dist/casa.js +0 -46
  8. package/dist/lib/CasaTemplateLoader.d.ts +0 -29
  9. package/dist/lib/CasaTemplateLoader.js +0 -74
  10. package/dist/lib/JourneyContext.d.ts +0 -297
  11. package/dist/lib/JourneyContext.js +0 -581
  12. package/dist/lib/MutableRouter.d.ts +0 -155
  13. package/dist/lib/MutableRouter.js +0 -277
  14. package/dist/lib/Plan.d.ts +0 -154
  15. package/dist/lib/Plan.js +0 -442
  16. package/dist/lib/ValidationError.d.ts +0 -74
  17. package/dist/lib/ValidationError.js +0 -159
  18. package/dist/lib/ValidatorFactory.d.ts +0 -83
  19. package/dist/lib/ValidatorFactory.js +0 -106
  20. package/dist/lib/configuration-ingestor.d.ts +0 -262
  21. package/dist/lib/configuration-ingestor.js +0 -490
  22. package/dist/lib/configure.d.ts +0 -90
  23. package/dist/lib/configure.js +0 -192
  24. package/dist/lib/dirname.cjs +0 -1
  25. package/dist/lib/dirname.d.cts +0 -2
  26. package/dist/lib/end-session.d.ts +0 -13
  27. package/dist/lib/end-session.js +0 -43
  28. package/dist/lib/field.d.ts +0 -77
  29. package/dist/lib/field.js +0 -255
  30. package/dist/lib/index.d.ts +0 -14
  31. package/dist/lib/index.js +0 -54
  32. package/dist/lib/logger.d.ts +0 -9
  33. package/dist/lib/logger.js +0 -18
  34. package/dist/lib/nunjucks-filters.d.ts +0 -26
  35. package/dist/lib/nunjucks-filters.js +0 -90
  36. package/dist/lib/nunjucks.d.ts +0 -23
  37. package/dist/lib/nunjucks.js +0 -49
  38. package/dist/lib/utils.d.ts +0 -48
  39. package/dist/lib/utils.js +0 -111
  40. package/dist/lib/validators/dateObject.d.ts +0 -4
  41. package/dist/lib/validators/dateObject.js +0 -135
  42. package/dist/lib/validators/email.d.ts +0 -4
  43. package/dist/lib/validators/email.js +0 -46
  44. package/dist/lib/validators/inArray.d.ts +0 -4
  45. package/dist/lib/validators/inArray.js +0 -60
  46. package/dist/lib/validators/index.d.ts +0 -21
  47. package/dist/lib/validators/index.js +0 -47
  48. package/dist/lib/validators/nino.d.ts +0 -4
  49. package/dist/lib/validators/nino.js +0 -46
  50. package/dist/lib/validators/postalAddressObject.d.ts +0 -4
  51. package/dist/lib/validators/postalAddressObject.js +0 -123
  52. package/dist/lib/validators/regex.d.ts +0 -4
  53. package/dist/lib/validators/regex.js +0 -40
  54. package/dist/lib/validators/required.d.ts +0 -4
  55. package/dist/lib/validators/required.js +0 -56
  56. package/dist/lib/validators/strlen.d.ts +0 -4
  57. package/dist/lib/validators/strlen.js +0 -51
  58. package/dist/lib/validators/wordCount.d.ts +0 -5
  59. package/dist/lib/validators/wordCount.js +0 -54
  60. package/dist/lib/waypoint-url.d.ts +0 -23
  61. package/dist/lib/waypoint-url.js +0 -52
  62. package/dist/middleware/body-parser.d.ts +0 -1
  63. package/dist/middleware/body-parser.js +0 -24
  64. package/dist/middleware/csrf.d.ts +0 -1
  65. package/dist/middleware/csrf.js +0 -31
  66. package/dist/middleware/data.d.ts +0 -5
  67. package/dist/middleware/data.js +0 -53
  68. package/dist/middleware/dirname.cjs +0 -1
  69. package/dist/middleware/dirname.d.cts +0 -2
  70. package/dist/middleware/gather-fields.d.ts +0 -6
  71. package/dist/middleware/gather-fields.js +0 -48
  72. package/dist/middleware/i18n.d.ts +0 -4
  73. package/dist/middleware/i18n.js +0 -88
  74. package/dist/middleware/post.d.ts +0 -3
  75. package/dist/middleware/post.js +0 -57
  76. package/dist/middleware/pre.d.ts +0 -3
  77. package/dist/middleware/pre.js +0 -51
  78. package/dist/middleware/progress-journey.d.ts +0 -6
  79. package/dist/middleware/progress-journey.js +0 -80
  80. package/dist/middleware/sanitise-fields.d.ts +0 -5
  81. package/dist/middleware/sanitise-fields.js +0 -53
  82. package/dist/middleware/session.d.ts +0 -11
  83. package/dist/middleware/session.js +0 -121
  84. package/dist/middleware/skip-waypoint.d.ts +0 -5
  85. package/dist/middleware/skip-waypoint.js +0 -43
  86. package/dist/middleware/steer-journey.d.ts +0 -7
  87. package/dist/middleware/steer-journey.js +0 -62
  88. package/dist/middleware/validate-fields.d.ts +0 -7
  89. package/dist/middleware/validate-fields.js +0 -67
  90. package/dist/mjs/esm-wrapper.js +0 -11
  91. package/dist/mjs/package.json +0 -3
  92. package/dist/package.json +0 -3
  93. package/dist/routes/ancillary.d.ts +0 -11
  94. package/dist/routes/ancillary.js +0 -27
  95. package/dist/routes/dirname.cjs +0 -1
  96. package/dist/routes/dirname.d.cts +0 -2
  97. package/dist/routes/journey.d.ts +0 -8
  98. package/dist/routes/journey.js +0 -127
  99. package/dist/routes/static.d.ts +0 -26
  100. package/dist/routes/static.js +0 -68
@@ -1 +0,0 @@
1
- module.exports = __dirname;
@@ -1,2 +0,0 @@
1
- declare const _exports: string;
2
- export = _exports;
@@ -1,6 +0,0 @@
1
- declare function _default({ waypoint, fields, }: {
2
- waypoint: string;
3
- fields?: import("../lib/field").PageField[] | undefined;
4
- }): any[];
5
- export default _default;
6
- export type PageField = import('../lib/field').PageField;
@@ -1,48 +0,0 @@
1
- "use strict";
2
- // Gather the field data from `req.body` into the current JourneyContext
3
- // - Store in the current session
4
- // - Update the user's journey context with the new data
5
- // - Remove validation date of JourneyContext so it can re-evaluted
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
11
- /**
12
- * @typedef {import('../lib/field').PageField} PageField
13
- */
14
- /**
15
- * Gather the field data from `req.body` into the current JourneyContext
16
- * - Store in the current session
17
- * - Update the user's journey context with the new data
18
- * - Remove validation date of JourneyContext so it can re-evaluted
19
- *
20
- * @param {object} obj Options
21
- * @param {string} obj.waypoint Waypoint
22
- * @param {PageField[]} [obj.fields=[]] Fields
23
- * @returns {Array} Array of middleware
24
- */
25
- exports.default = ({ waypoint, fields = [], }) => [
26
- (req, res, next) => {
27
- // Store a copy of the journey context before modifying it. This is useful
28
- // for any comparison work that may be done in subseqent middleware.
29
- req.casa.archivedJourneyContext = JourneyContext_js_1.default.fromContext(req.casa.journeyContext);
30
- // Ignore data for any non-persistent fields
31
- const persistentBody = Object.create(null);
32
- for (let i = 0, l = fields.length; i < l; i++) {
33
- if (fields[i].meta.persist && fields[i].getValue(req.body) !== undefined) {
34
- persistentBody[fields[i].name] = fields[i].getValue(req.body);
35
- }
36
- }
37
- // Update data and validation context in the current request, and store
38
- req.casa.journeyContext.setDataForPage(waypoint, persistentBody);
39
- req.casa.journeyContext.removeValidationStateForPage(waypoint);
40
- JourneyContext_js_1.default.putContext(req.session, req.casa.journeyContext);
41
- // TODO: Once feature we might like here is to invalidate specific pages
42
- // based on the change that has just happened, to force those pages to be
43
- // visited again. The main use case is to cater for a change in content on
44
- // those pages that fundamentally alter the context of the question being asked,
45
- // and so should be asked again. For example, "Your address" vs "You and your partner's address"
46
- next();
47
- },
48
- ];
@@ -1,4 +0,0 @@
1
- export default function i18nMiddleware({ languages, directories, }: {
2
- languages?: string[] | undefined;
3
- directories?: any[] | undefined;
4
- }): import("express-serve-static-core").Handler[];
@@ -1,88 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const i18next_1 = __importDefault(require("i18next"));
7
- const i18next_http_middleware_1 = require("i18next-http-middleware");
8
- const path_1 = require("path");
9
- const fs_1 = require("fs");
10
- const deepmerge_1 = __importDefault(require("deepmerge"));
11
- const js_yaml_1 = __importDefault(require("js-yaml"));
12
- const logger_js_1 = __importDefault(require("../lib/logger.js"));
13
- const log = (0, logger_js_1.default)('middleware.i18n');
14
- const loadJson = (file) => {
15
- // Strip out newlines (this is a legacy feature which we're keeping for
16
- // backwards compatibility).
17
- const json = (0, fs_1.readFileSync)(file, 'utf8');
18
- return JSON.parse(json.replace(/[\r\n]/g, ''));
19
- };
20
- const loadYaml = (file) => js_yaml_1.default.load((0, fs_1.readFileSync)(file, 'utf8'));
21
- const extract = (file) => {
22
- const ext = /.yaml$/i.test(file) ? '.yaml' : '.json';
23
- const data = ext === '.yaml' ? loadYaml(file) : loadJson(file);
24
- return {
25
- ns: (0, path_1.basename)(file, ext),
26
- data,
27
- };
28
- };
29
- const loadResources = (languages, directories) => {
30
- const store = Object.create(null);
31
- languages.forEach((language) => {
32
- store[language] = Object.create(null);
33
- directories.forEach((basedir) => {
34
- const dir = (0, path_1.resolve)(basedir, language);
35
- if (!(0, fs_1.existsSync)(dir)) {
36
- return;
37
- }
38
- log.info('Loading %s language from %s ...', language, dir);
39
- (0, fs_1.readdirSync)(dir).forEach((file) => {
40
- const { ns, data } = extract((0, path_1.resolve)(dir, file));
41
- if (store[language][ns] === undefined) {
42
- store[language][ns] = Object.create(null);
43
- }
44
- store[language][ns] = (0, deepmerge_1.default)(store[language][ns], data);
45
- });
46
- });
47
- });
48
- return store;
49
- };
50
- function i18nMiddleware({ languages = ['en', 'cy'], directories = [], }) {
51
- // Load _all_ translations, from all directories into memory.
52
- const resources = loadResources(languages, directories);
53
- // Configure i18next
54
- const i18nInstance = i18next_1.default.createInstance();
55
- i18nInstance
56
- .use(i18next_http_middleware_1.LanguageDetector)
57
- .init({
58
- initImmediate: false,
59
- supportedLngs: languages,
60
- fallbackLng: false,
61
- defaultNS: 'common',
62
- // debug: true,
63
- // All translation resources
64
- resources,
65
- // LanguageDetector options
66
- detection: {
67
- lookupQuerystring: 'lang',
68
- lookupSession: 'language',
69
- order: ['querystring', 'session'],
70
- },
71
- });
72
- // 2 middleware: one to read/set the session language, and one to enhance the
73
- // req/res objects with i18n features
74
- return [
75
- (req, res, next) => {
76
- if (!req.session.language) {
77
- /* eslint-disable-next-line prefer-destructuring */
78
- req.session.language = languages[0];
79
- }
80
- if ((req === null || req === void 0 ? void 0 : req.query.lang) && languages.includes(req.query.lang)) {
81
- req.session.language = String(req.query.lang);
82
- }
83
- next();
84
- },
85
- (0, i18next_http_middleware_1.handle)(i18nInstance),
86
- ];
87
- }
88
- exports.default = i18nMiddleware;
@@ -1,3 +0,0 @@
1
- export default function postMiddleware({ mountUrl, }: {
2
- mountUrl: any;
3
- }): ((err: any, req: any, res: any, next: any) => any)[];
@@ -1,57 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- // 2 middleware: one as a fallback 404 handler, one to handle thrown errors
7
- const logger_js_1 = __importDefault(require("../lib/logger.js"));
8
- const log = (0, logger_js_1.default)('middleware:post');
9
- function postMiddleware({ mountUrl, }) {
10
- return [
11
- (req, res) => {
12
- res.render('casa/errors/404.njk');
13
- },
14
- /* eslint-disable-next-line no-unused-vars */
15
- (err, req, res, next) => {
16
- var _a;
17
- // In some cases, an error may have been thrown before the template assets
18
- // have had a chance to initialise. So we use a hardcoded template in
19
- // these cases to ensure the user sees an appropriate message.
20
- let TEMPLATE = 'casa/errors/500.njk';
21
- if (!res.locals.t) {
22
- res.locals.t = () => ('');
23
- res.locals.casa = Object.assign(Object.assign({}, (_a = res.locals) === null || _a === void 0 ? void 0 : _a.casa), { mountUrl });
24
- TEMPLATE = 'casa/errors/static.njk';
25
- }
26
- // CSRF token is invalid in some way
27
- if ((err === null || err === void 0 ? void 0 : err.code) === 'EBADCSRFTOKEN') {
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' });
30
- }
31
- // Body parsing verification check failed
32
- if ((err === null || err === void 0 ? void 0 : err.type) === 'entity.verify.failed') {
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' });
35
- }
36
- // Too many parameters submitted
37
- if ((err === null || err === void 0 ? void 0 : err.type) === 'parameters.too.many') {
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' });
40
- }
41
- // Overall payload too large
42
- if ((err === null || err === void 0 ? void 0 : err.type) === 'entity.too.large') {
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' });
45
- }
46
- // Unaccept request method
47
- if ((err === null || err === void 0 ? void 0 : err.code) === 'unaccepted_request_method') {
48
- log.info(err.message);
49
- return res.status(400).render(TEMPLATE, { errorCode: 'unaccepted_request_method' });
50
- }
51
- // Unknown error
52
- log.error(`Unknown error: ${err.message}; stacktrace: ${err.stack}`);
53
- return res.status(200).render(TEMPLATE);
54
- },
55
- ];
56
- }
57
- exports.default = postMiddleware;
@@ -1,3 +0,0 @@
1
- /// <reference types="node" />
2
- declare function _default(): ((req: import("http").IncomingMessage, res: import("http").ServerResponse, next: (err?: unknown) => void) => void)[];
3
- export default _default;
@@ -1,51 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const crypto_1 = require("crypto");
7
- const helmet_1 = __importDefault(require("helmet"));
8
- exports.default = () => [
9
- // Only allow certain request methods
10
- (req, res, next) => {
11
- if (req.method !== 'GET' && req.method !== 'POST') {
12
- const err = new Error(`Unaccepted request method, "${String(req.method).substr(0, 7)}"`);
13
- err.code = 'unaccepted_request_method';
14
- next(err);
15
- }
16
- else {
17
- next();
18
- }
19
- },
20
- // Prevent caching response in any intermediaries by default, in case it
21
- // contains sensitive data.
22
- // The `no-store` setting is to specifically disable the bfcache and prevent
23
- // possible leakage of information.
24
- (req, res, next) => {
25
- res.set('cache-control', 'no-cache, no-store, must-revalidate, private');
26
- res.set('pragma', 'no-cache');
27
- res.set('expires', 0);
28
- res.set('x-robots-tag', 'noindex, nofollow');
29
- next();
30
- },
31
- // Generate nonces ready for use in Content-Security-Policy header and
32
- // govuk-frontend template. This same none can be used wherever required.
33
- (req, res, next) => {
34
- res.locals.cspNonce = (0, crypto_1.randomBytes)(16).toString('hex');
35
- next();
36
- },
37
- // Helmet suite of headers
38
- (0, helmet_1.default)({
39
- // Allows GA which is typically used, and a known inline script nonce
40
- contentSecurityPolicy: {
41
- useDefaults: true,
42
- directives: {
43
- 'script-src': ["'self'", 'www.google-analytics.com', 'www.googletagmanager.com', (req, res) => `'nonce-${res.locals.cspNonce}'`],
44
- 'style-src': ["'self'", 'https:', (req, res) => `'nonce-${res.locals.cspNonce}'`],
45
- 'form-action': ["'self'"],
46
- },
47
- },
48
- // // Require referrer to aid navigation
49
- // referrerPolicy: 'no-referrer, same-origin',
50
- }),
51
- ];
@@ -1,6 +0,0 @@
1
- declare function _default({ waypoint, plan, mountUrl, }: {
2
- waypoint: any;
3
- plan: any;
4
- mountUrl: any;
5
- }): ((req: any, res: any, next: any) => void)[];
6
- export default _default;
@@ -1,80 +0,0 @@
1
- "use strict";
2
- // Determine where to take the user next
3
- // We assume that the waypoint has been validated prior to reaching this
4
- // middleware.
5
- var __importDefault = (this && this.__importDefault) || function (mod) {
6
- return (mod && mod.__esModule) ? mod : { "default": mod };
7
- };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- const Plan_js_1 = __importDefault(require("../lib/Plan.js"));
10
- const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
11
- const waypoint_url_js_1 = __importDefault(require("../lib/waypoint-url.js"));
12
- const logger_js_1 = __importDefault(require("../lib/logger.js"));
13
- const log = (0, logger_js_1.default)('middleware:progress-journey');
14
- const saveAndRedirect = (session, journeyContext, url, res, next) => {
15
- JourneyContext_js_1.default.putContext(session, journeyContext);
16
- session.save((err) => {
17
- if (err) {
18
- next(err);
19
- }
20
- res.redirect(302, url);
21
- });
22
- };
23
- exports.default = ({ waypoint, plan, mountUrl, }) => [
24
- (req, res, next) => {
25
- // Determine the next available waypoint after the current one
26
- const traversed = plan.traverse(req.casa.journeyContext);
27
- const currentIndex = traversed.indexOf(waypoint);
28
- const nextIndex = Math.max(currentIndex < 0 ? traversed.length - 1 : 0, Math.min(currentIndex + 1, traversed.length - 1));
29
- const nextWaypoint = traversed[nextIndex];
30
- log.trace(`currentIndex = ${currentIndex}, nextIndex = ${nextIndex}, currentWaypoint = ${waypoint}, nextWaypoint = ${nextWaypoint}`);
31
- // Edit mode
32
- // Attempt to take the user back to their original URL. We rely on the
33
- // `steer-journey` middleware to prevent the user going too far ahead in
34
- // their permitted journey. Bear in mind that the `editOrigin` may not be
35
- // a waypoint at all, but a route path for a custom endpoint, so we can't
36
- // safely do a traversal check here.
37
- //
38
- // The edit mode URL params will be kept on this redirect. This means the
39
- // user can keep "jumping" to the next _changed_ waypoint, until they get
40
- // back to the original URL.
41
- //
42
- // Devs should use the `events` mechanism to mark waypoints as invalid if
43
- // they want to force the user to re-visit particular waypoints during this
44
- // "jumping" phase.
45
- if (req.casa.editMode && req.casa.editOrigin) {
46
- const url = new URL(req.casa.editOrigin, 'https://placeholder.test/');
47
- url.searchParams.append('edit', 'true');
48
- url.searchParams.append('editorigin', req.casa.editOrigin);
49
- const redirectUrl = (0, waypoint_url_js_1.default)({ waypoint: url.pathname }) + url.search.toString();
50
- log.debug(`Edit mode detected; redirecting to ${redirectUrl}`);
51
- return saveAndRedirect(req.session, req.casa.journeyContext, redirectUrl, res, next);
52
- }
53
- // If the next URL is an "exit node", we need to flag that node as
54
- // being validated so that subsequent traversals of this journey continue
55
- // correctly to any waypoints leading on from this one.
56
- // This effectively says that the other Plan linked to by the exit node is
57
- // complete, but of course that may not be the case.
58
- // It would be prudent for developers to add a conditions to the route to
59
- // check is this is the case, eg
60
- // setRoute('a', 'b');
61
- // setRoute('b', 'url:///otherapp/')
62
- // setRoute('url:////otherapp/', 'c', (r, c) => checkIfOtherAppIsFinished())
63
- if (Plan_js_1.default.isExitNode(nextWaypoint)) {
64
- log.trace(`Next waypoint is an exit node; clearing validation state on ${nextWaypoint}`);
65
- req.casa.journeyContext.clearValidationErrorsForPage(nextWaypoint);
66
- JourneyContext_js_1.default.putContext(req.session, req.casa.journeyContext);
67
- }
68
- // Construct the next url
69
- const nextUrl = (0, waypoint_url_js_1.default)({
70
- waypoint: nextWaypoint,
71
- mountUrl,
72
- journeyContext: req.casa.journeyContext,
73
- edit: req.casa.editMode,
74
- editOrigin: req.casa.editOrigin,
75
- });
76
- // Save and move on
77
- log.trace(`Redirecting to ${nextUrl}`);
78
- return saveAndRedirect(req.session, req.casa.journeyContext, nextUrl, res, next);
79
- },
80
- ];
@@ -1,5 +0,0 @@
1
- declare function _default({ waypoint, fields, }: {
2
- waypoint: any;
3
- fields?: any[] | undefined;
4
- }): ((req: any, res: any, next: any) => void)[];
5
- export default _default;
@@ -1,53 +0,0 @@
1
- "use strict";
2
- // Sanitise the fields submitted from a form
3
- // - Coerce each field to its correct type
4
- // - Remove an extraneous fields that are not know to the application
5
- var __importDefault = (this && this.__importDefault) || function (mod) {
6
- return (mod && mod.__esModule) ? mod : { "default": mod };
7
- };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- const lodash_1 = __importDefault(require("lodash"));
10
- const field_js_1 = __importDefault(require("../lib/field.js"));
11
- const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
12
- exports.default = ({ waypoint, fields = [], }) => {
13
- // Add some common, transient fields to ensure they survive beyond this sanitisation process
14
- fields.push((0, field_js_1.default)('_csrf', { persist: false }).processor((value) => String(value)));
15
- fields.push((0, field_js_1.default)('contextid', { persist: false }).processor((value) => String(value)));
16
- fields.push((0, field_js_1.default)('edit', { persist: false }).processor((value) => String(value)));
17
- fields.push((0, field_js_1.default)('editorigin', { persist: false }).processor((value) => String(value)));
18
- // Middleware
19
- return [
20
- (req, res, next) => {
21
- // First, prune all undefined, or unknown fields from `req.body` (i.e.
22
- // those that do not have an entry in `fields`)
23
- const prunedBody = Object.create(null);
24
- for (let i = 0, l = fields.length; i < l; i++) {
25
- if (lodash_1.default.has(req.body, fields[i].name) && req.body[fields[i].name] !== undefined) {
26
- prunedBody[fields[i].name] = req.body[fields[i].name];
27
- }
28
- }
29
- // TODO: the journey context passed to the processors and conditions, with
30
- // data set to the "prunedBody"
31
- const journeyContext = JourneyContext_js_1.default.fromContext(req.casa.journeyContext);
32
- journeyContext.setDataForPage(waypoint, prunedBody);
33
- // const journeyContext = {};
34
- // Second, prune any fields that do not pass the validation conditional,
35
- // and process those that do.
36
- const sanitisedBody = Object.create(null);
37
- for (let i = 0, l = fields.length; i < l; i++) {
38
- const field = fields[i];
39
- const fieldValue = field.getValue(prunedBody); // prunedBody[field.name];
40
- if (fieldValue !== undefined && field.testConditions({
41
- fieldValue,
42
- waypoint,
43
- journeyContext,
44
- })) {
45
- field.putValue(sanitisedBody, field.applyProcessors(fieldValue));
46
- }
47
- }
48
- // Finally, write the sanitised body back to the request object
49
- req.body = sanitisedBody;
50
- next();
51
- },
52
- ];
53
- };
@@ -1,11 +0,0 @@
1
- export default function sessionMiddleware({ cookieParserMiddleware, secret, name, secure, ttl, mountUrl, cookieSameSite, cookiePath, store, }: {
2
- cookieParserMiddleware: any;
3
- secret: any;
4
- name: any;
5
- secure: any;
6
- ttl: any;
7
- mountUrl?: string | undefined;
8
- cookieSameSite?: boolean | undefined;
9
- cookiePath?: string | undefined;
10
- store?: any;
11
- }): any[];
@@ -1,121 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- var __importDefault = (this && this.__importDefault) || function (mod) {
22
- return (mod && mod.__esModule) ? mod : { "default": mod };
23
- };
24
- Object.defineProperty(exports, "__esModule", { value: true });
25
- // A last-modified cookie is used to control whether the end user sees a
26
- // session-timeout page, or they are simply given a new session without
27
- // interrupting their journey.
28
- const express_session_1 = __importStar(require("express-session"));
29
- const logger_js_1 = __importDefault(require("../lib/logger.js"));
30
- const log = (0, logger_js_1.default)('middleware:session');
31
- // 3 middleware:
32
- // - set the session cookie
33
- // - parse request cookies
34
- // - handle expiry of server-side session
35
- function sessionMiddleware({ cookieParserMiddleware, secret, name, secure, ttl, mountUrl = '/', cookieSameSite = true, cookiePath = '/', store = new express_session_1.MemoryStore(), }) {
36
- const commonCookieOptions = {
37
- httpOnly: true,
38
- path: cookiePath,
39
- secure,
40
- };
41
- if (cookieSameSite !== false) {
42
- commonCookieOptions.sameSite = cookieSameSite === true ? 'Strict' : cookieSameSite;
43
- }
44
- const ttlGrace = 1800; // user will see session-timeout if session expires within 30mins
45
- const touchCookieName = `${name}.t`;
46
- const touchCookieOptions = Object.assign(Object.assign({}, commonCookieOptions), { maxAge: (ttl + ttlGrace) * 1000, signed: true });
47
- const touchCookie = (res) => {
48
- // Touch cookie expiry is 3a short period after the session ttl. This gives
49
- // a small period of time where a user will see the session-timeout message,
50
- // which is important to avoid the confusion of simply being redirected back
51
- // to the start of their journey.
52
- res.cookie(touchCookieName, (new Date(Date.now())).toUTCString(), touchCookieOptions);
53
- };
54
- const removeCookie = (res) => {
55
- res.clearCookie(touchCookieName, touchCookieOptions);
56
- };
57
- return [
58
- (0, express_session_1.default)({
59
- secret,
60
- name,
61
- saveUninitialized: false,
62
- resave: false,
63
- cookie: Object.assign(Object.assign({}, commonCookieOptions), { maxAge: null }),
64
- store,
65
- }),
66
- cookieParserMiddleware,
67
- (req, res, next) => {
68
- var _a, _b;
69
- let lastModified = Date.parse(String((_a = req.signedCookies[touchCookieName]) !== null && _a !== void 0 ? _a : '1970-01-01T00:00:00+0000'));
70
- lastModified = Number.isNaN(lastModified) ? 0 : Math.floor(lastModified * 0.001);
71
- const age = Math.floor(Date.now() * 0.001) - lastModified;
72
- if (lastModified === 0) {
73
- // New session, or grace period cookie no longer available after
74
- // expiring; generate a new session, and create grace-period cookie.
75
- // This will invalidate any CSRF tokens, so by letting the request POST
76
- // requests through the user may see a 500 error response.
77
- log.info('Session is new, or grace period has expired. Regenerating session.');
78
- req.session.regenerate((err) => {
79
- if (err) {
80
- next(err);
81
- }
82
- else {
83
- touchCookie(res);
84
- if (req.method === 'POST') {
85
- log.info('The CSRF token for this POST request will now be invalid for this regenerated session. Redirecting to app mount point.');
86
- res.redirect(302, mountUrl);
87
- }
88
- else {
89
- next();
90
- }
91
- }
92
- });
93
- }
94
- else if (age > ttl) {
95
- // Cookie has become stale and server session will have been removed;
96
- // redirect to session-timeout
97
- log.info('Session has timed out within grace period. Destroying session and redirecting to timeout page.');
98
- const language = (_b = req.session.language) !== null && _b !== void 0 ? _b : 'en';
99
- req.session.destroy((err) => {
100
- if (err) {
101
- next(err);
102
- }
103
- else {
104
- removeCookie(res);
105
- const params = new URLSearchParams({
106
- referrer: req.originalUrl,
107
- lang: language,
108
- });
109
- res.redirect(302, `${mountUrl}session-timeout?${params.toString()}`);
110
- }
111
- });
112
- }
113
- else {
114
- // Touch cookie and continue
115
- touchCookie(res);
116
- next();
117
- }
118
- },
119
- ];
120
- }
121
- exports.default = sessionMiddleware;
@@ -1,5 +0,0 @@
1
- declare function _default({ waypoint, mountUrl, }: {
2
- waypoint: any;
3
- mountUrl: any;
4
- }): ((req: any, res: any, next: any) => any)[];
5
- export default _default;
@@ -1,43 +0,0 @@
1
- "use strict";
2
- // Mark a waypoint as skipped
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const lodash_1 = __importDefault(require("lodash"));
8
- const JourneyContext_js_1 = __importDefault(require("../lib/JourneyContext.js"));
9
- const waypoint_url_js_1 = __importDefault(require("../lib/waypoint-url.js"));
10
- const logger_js_1 = __importDefault(require("../lib/logger.js"));
11
- const { has } = lodash_1.default;
12
- const log = (0, logger_js_1.default)('middleware:skip-waypoint');
13
- exports.default = ({ waypoint, mountUrl, }) => [
14
- (req, res, next) => {
15
- if (!has(req.query, 'skipto')) {
16
- return next();
17
- }
18
- const skipTo = String(req.query.skipto);
19
- // Inject a special `__skipped__` attribute into this waypoint's data
20
- log.info(`Marking waypoint "${waypoint}" as skipped`);
21
- req.casa.journeyContext.clearValidationErrorsForPage(waypoint);
22
- req.casa.journeyContext.setDataForPage(waypoint, {
23
- __skipped__: true,
24
- });
25
- JourneyContext_js_1.default.putContext(req.session, req.casa.journeyContext);
26
- const redirectUrl = (0, waypoint_url_js_1.default)({
27
- mountUrl,
28
- waypoint: skipTo,
29
- edit: req.editMode,
30
- editOrigin: req.editOriginUrl,
31
- journeyContext: req.casa.journeyContext,
32
- });
33
- log.debug(`Will redirect to "${redirectUrl}" after skipping "${waypoint}"`);
34
- return req.session.save((err) => {
35
- if (err) {
36
- next(err);
37
- }
38
- else {
39
- res.redirect(302, redirectUrl);
40
- }
41
- });
42
- },
43
- ];
@@ -1,7 +0,0 @@
1
- declare function _default({ waypoint, plan, mountUrl, }: {
2
- waypoint: string;
3
- plan: Plan;
4
- mountUrl: string;
5
- }): void;
6
- export default _default;
7
- export type Plan = typeof import("../lib/Plan");