@dwp/govuk-casa 9.0.0 → 9.1.0
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/README.md +9 -9
- package/dist/assets/css/casa.css +1 -1
- package/dist/assets/css/casa.css.map +1 -1
- package/dist/casa.d.ts +122 -95
- package/dist/casa.js +119 -86
- package/dist/casa.js.map +1 -1
- package/dist/lib/CasaTemplateLoader.d.ts +4 -4
- package/dist/lib/CasaTemplateLoader.js +16 -16
- package/dist/lib/CasaTemplateLoader.js.map +1 -1
- package/dist/lib/JourneyContext.d.ts +38 -40
- package/dist/lib/JourneyContext.js +81 -75
- package/dist/lib/JourneyContext.js.map +1 -1
- package/dist/lib/MutableRouter.d.ts +40 -41
- package/dist/lib/MutableRouter.js +64 -71
- package/dist/lib/MutableRouter.js.map +1 -1
- package/dist/lib/Plan.d.ts +29 -26
- package/dist/lib/Plan.js +85 -71
- package/dist/lib/Plan.js.map +1 -1
- package/dist/lib/ValidationError.d.ts +16 -15
- package/dist/lib/ValidationError.js +21 -20
- package/dist/lib/ValidationError.js.map +1 -1
- package/dist/lib/ValidatorFactory.d.ts +15 -13
- package/dist/lib/ValidatorFactory.js +14 -12
- package/dist/lib/ValidatorFactory.js.map +1 -1
- package/dist/lib/configuration-ingestor.d.ts +37 -40
- package/dist/lib/configuration-ingestor.js +93 -93
- package/dist/lib/configuration-ingestor.js.map +1 -1
- package/dist/lib/configure.d.ts +6 -6
- package/dist/lib/configure.js +14 -12
- package/dist/lib/configure.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -3
- package/dist/lib/constants.js +9 -11
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/context-id-generators.d.ts +3 -5
- package/dist/lib/context-id-generators.js +7 -6
- package/dist/lib/context-id-generators.js.map +1 -1
- package/dist/lib/end-session.d.ts +4 -4
- package/dist/lib/end-session.js +5 -5
- package/dist/lib/field.d.ts +20 -18
- package/dist/lib/field.js +35 -48
- package/dist/lib/field.js.map +1 -1
- package/dist/lib/index.d.ts +13 -13
- package/dist/lib/logger.d.ts +7 -6
- package/dist/lib/logger.js +7 -7
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/mount.d.ts +5 -5
- package/dist/lib/mount.js +11 -10
- package/dist/lib/mount.js.map +1 -1
- package/dist/lib/nunjucks-filters.d.ts +10 -12
- package/dist/lib/nunjucks-filters.js +35 -35
- package/dist/lib/nunjucks-filters.js.map +1 -1
- package/dist/lib/nunjucks.d.ts +7 -5
- package/dist/lib/nunjucks.js +10 -8
- package/dist/lib/nunjucks.js.map +1 -1
- package/dist/lib/utils.d.ts +19 -19
- package/dist/lib/utils.js +62 -55
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/validators/dateObject.d.ts +29 -22
- package/dist/lib/validators/dateObject.js +58 -49
- package/dist/lib/validators/dateObject.js.map +1 -1
- package/dist/lib/validators/email.d.ts +4 -4
- package/dist/lib/validators/email.js +4 -4
- package/dist/lib/validators/inArray.d.ts +4 -4
- package/dist/lib/validators/inArray.js +7 -8
- package/dist/lib/validators/inArray.js.map +1 -1
- package/dist/lib/validators/index.d.ts +10 -10
- package/dist/lib/validators/index.js +1 -3
- package/dist/lib/validators/index.js.map +1 -1
- package/dist/lib/validators/nino.d.ts +9 -8
- package/dist/lib/validators/nino.js +14 -10
- package/dist/lib/validators/nino.js.map +1 -1
- package/dist/lib/validators/postalAddressObject.d.ts +37 -24
- package/dist/lib/validators/postalAddressObject.js +65 -46
- package/dist/lib/validators/postalAddressObject.js.map +1 -1
- package/dist/lib/validators/range.d.ts +12 -8
- package/dist/lib/validators/range.js +11 -9
- package/dist/lib/validators/range.js.map +1 -1
- package/dist/lib/validators/regex.d.ts +4 -4
- package/dist/lib/validators/regex.js +5 -5
- package/dist/lib/validators/required.d.ts +6 -6
- package/dist/lib/validators/required.js +9 -11
- package/dist/lib/validators/required.js.map +1 -1
- package/dist/lib/validators/strlen.d.ts +12 -8
- package/dist/lib/validators/strlen.js +13 -11
- package/dist/lib/validators/strlen.js.map +1 -1
- package/dist/lib/validators/wordCount.d.ts +12 -8
- package/dist/lib/validators/wordCount.js +15 -11
- package/dist/lib/validators/wordCount.js.map +1 -1
- package/dist/lib/waypoint-url.d.ts +16 -13
- package/dist/lib/waypoint-url.js +39 -36
- package/dist/lib/waypoint-url.js.map +1 -1
- package/dist/middleware/body-parser.d.ts +1 -1
- package/dist/middleware/body-parser.js +6 -6
- package/dist/middleware/body-parser.js.map +1 -1
- package/dist/middleware/data.d.ts +1 -1
- package/dist/middleware/data.js +8 -7
- package/dist/middleware/data.js.map +1 -1
- package/dist/middleware/gather-fields.d.ts +2 -2
- package/dist/middleware/gather-fields.js +6 -4
- package/dist/middleware/gather-fields.js.map +1 -1
- package/dist/middleware/i18n.js +13 -15
- package/dist/middleware/i18n.js.map +1 -1
- package/dist/middleware/post.js +30 -18
- package/dist/middleware/post.js.map +1 -1
- package/dist/middleware/pre.d.ts +2 -2
- package/dist/middleware/pre.js +46 -27
- package/dist/middleware/pre.js.map +1 -1
- package/dist/middleware/progress-journey.d.ts +1 -1
- package/dist/middleware/progress-journey.js +5 -5
- package/dist/middleware/progress-journey.js.map +1 -1
- package/dist/middleware/sanitise-fields.d.ts +1 -1
- package/dist/middleware/sanitise-fields.js +13 -11
- package/dist/middleware/sanitise-fields.js.map +1 -1
- package/dist/middleware/serve-first-waypoint.d.ts +3 -3
- package/dist/middleware/serve-first-waypoint.js +8 -6
- package/dist/middleware/serve-first-waypoint.js.map +1 -1
- package/dist/middleware/session.js +14 -11
- package/dist/middleware/session.js.map +1 -1
- package/dist/middleware/skip-waypoint.d.ts +1 -1
- package/dist/middleware/skip-waypoint.js +3 -3
- package/dist/middleware/skip-waypoint.js.map +1 -1
- package/dist/middleware/steer-journey.d.ts +1 -1
- package/dist/middleware/steer-journey.js +16 -14
- package/dist/middleware/steer-journey.js.map +1 -1
- package/dist/middleware/strip-proxy-path.d.ts +1 -1
- package/dist/middleware/strip-proxy-path.js +3 -3
- package/dist/middleware/strip-proxy-path.js.map +1 -1
- package/dist/middleware/validate-fields.d.ts +1 -1
- package/dist/middleware/validate-fields.js +2 -5
- package/dist/middleware/validate-fields.js.map +1 -1
- package/dist/routes/ancillary.d.ts +3 -3
- package/dist/routes/ancillary.js +4 -4
- package/dist/routes/ancillary.js.map +1 -1
- package/dist/routes/journey.d.ts +2 -2
- package/dist/routes/journey.js +91 -39
- package/dist/routes/journey.js.map +1 -1
- package/dist/routes/static.d.ts +7 -5
- package/dist/routes/static.js +20 -19
- package/dist/routes/static.js.map +1 -1
- package/package.json +19 -18
- package/src/casa.js +133 -100
- package/src/lib/CasaTemplateLoader.js +24 -19
- package/src/lib/JourneyContext.js +138 -107
- package/src/lib/MutableRouter.js +72 -74
- package/src/lib/Plan.js +145 -97
- package/src/lib/ValidationError.js +25 -21
- package/src/lib/ValidatorFactory.js +17 -13
- package/src/lib/configuration-ingestor.js +147 -110
- package/src/lib/configure.js +34 -32
- package/src/lib/constants.js +9 -11
- package/src/lib/context-id-generators.js +40 -43
- package/src/lib/end-session.js +6 -6
- package/src/lib/field.js +69 -58
- package/src/lib/index.js +12 -12
- package/src/lib/logger.js +9 -9
- package/src/lib/mount.js +70 -74
- package/src/lib/nunjucks-filters.js +56 -59
- package/src/lib/nunjucks.js +23 -18
- package/src/lib/utils.js +78 -57
- package/src/lib/validators/dateObject.js +71 -60
- package/src/lib/validators/email.js +8 -8
- package/src/lib/validators/inArray.js +10 -11
- package/src/lib/validators/index.js +12 -14
- package/src/lib/validators/nino.js +29 -15
- package/src/lib/validators/postalAddressObject.js +87 -63
- package/src/lib/validators/range.js +14 -12
- package/src/lib/validators/regex.js +8 -8
- package/src/lib/validators/required.js +16 -16
- package/src/lib/validators/strlen.js +16 -14
- package/src/lib/validators/wordCount.js +22 -14
- package/src/lib/waypoint-url.js +64 -46
- package/src/middleware/body-parser.js +10 -10
- package/src/middleware/csrf.js +1 -1
- package/src/middleware/data.js +28 -24
- package/src/middleware/gather-fields.js +10 -9
- package/src/middleware/i18n.js +35 -37
- package/src/middleware/post.js +41 -21
- package/src/middleware/pre.js +62 -41
- package/src/middleware/progress-journey.js +32 -18
- package/src/middleware/sanitise-fields.js +43 -20
- package/src/middleware/serve-first-waypoint.js +14 -12
- package/src/middleware/session.js +74 -61
- package/src/middleware/skip-waypoint.js +7 -9
- package/src/middleware/steer-journey.js +40 -28
- package/src/middleware/strip-proxy-path.js +8 -7
- package/src/middleware/validate-fields.js +5 -12
- package/src/routes/ancillary.js +5 -7
- package/src/routes/journey.js +159 -85
- package/src/routes/static.js +62 -29
- package/views/casa/components/character-count/README.md +2 -2
- package/views/casa/components/checkboxes/README.md +6 -6
- package/views/casa/components/date-input/README.md +7 -7
- package/views/casa/components/input/README.md +2 -2
- package/views/casa/components/journey-form/README.md +33 -14
- package/views/casa/components/postal-address-object/README.md +4 -4
- package/views/casa/components/radios/README.md +6 -6
- package/views/casa/components/select/README.md +6 -6
- package/views/casa/components/textarea/README.md +2 -2
- package/views/casa/layouts/main.njk +2 -1
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
/* eslint-disable class-methods-use-this */
|
|
2
|
-
import lodash from
|
|
2
|
+
import lodash from "lodash";
|
|
3
3
|
|
|
4
4
|
const { isPlainObject } = lodash; // CommonJS
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
+
* @typedef {import("../casa").ErrorMessageConfig} ErrorMessageConfig
|
|
7
8
|
* @access private
|
|
8
|
-
* @typedef {import('../casa').ErrorMessageConfig} ErrorMessageConfig
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
+
* @typedef {import("./index").JourneyContext} JourneyContext
|
|
12
13
|
* @access private
|
|
13
|
-
* @typedef {import('./index').JourneyContext} JourneyContext
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
+
* @typedef {import("./index").ValidationError} ValidationError
|
|
17
18
|
* @access private
|
|
18
|
-
* @typedef {import('./index').ValidationError} ValidationError
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
+
* @typedef {import("../casa").ValidateContext} ValidateContext
|
|
22
23
|
* @access private
|
|
23
|
-
* @typedef {import('../casa').ValidateContext} ValidateContext
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
+
* @typedef {import("../casa").Validator} Validator
|
|
27
28
|
* @access private
|
|
28
|
-
* @typedef {import('../casa').Validator} Validator
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -34,28 +34,29 @@ const { isPlainObject } = lodash; // CommonJS
|
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* @class
|
|
38
37
|
* @memberof module:@dwp/govuk-casa
|
|
38
|
+
* @class
|
|
39
39
|
*/
|
|
40
40
|
export default class ValidatorFactory {
|
|
41
41
|
/**
|
|
42
42
|
* This is a convenience method that will return a consistently object
|
|
43
43
|
* structure containing validation and sanitisation methods.
|
|
44
44
|
*
|
|
45
|
-
* @param {ValidatorFactoryOptions} config Validator config (custom to each
|
|
45
|
+
* @param {ValidatorFactoryOptions} config Validator config (custom to each
|
|
46
|
+
* validator)
|
|
46
47
|
* @returns {Validator} Validator object
|
|
47
48
|
* @throws {TypeError} When configuration is invalid.
|
|
48
49
|
*/
|
|
49
50
|
static make(config = {}) {
|
|
50
51
|
if (!isPlainObject(config)) {
|
|
51
|
-
throw new TypeError(
|
|
52
|
+
throw new TypeError("Configuration must be an object");
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
const validator = Reflect.construct(this, [config]);
|
|
55
56
|
|
|
56
57
|
/* eslint-disable-next-line sonarjs/prefer-object-literal */
|
|
57
58
|
const instance = {};
|
|
58
|
-
instance.name = validator.name ||
|
|
59
|
+
instance.name = validator.name || "unknown";
|
|
59
60
|
instance.config = config;
|
|
60
61
|
instance.validate = validator.validate.bind(instance);
|
|
61
62
|
instance.sanitise = validator.sanitise.bind(instance);
|
|
@@ -68,11 +69,14 @@ export default class ValidatorFactory {
|
|
|
68
69
|
/**
|
|
69
70
|
* NEVER CALL THIS DIRECTLY. USE `make()`.
|
|
70
71
|
*
|
|
71
|
-
* @param {ValidatorFactoryOptions} config Validator config (custom to each
|
|
72
|
+
* @param {ValidatorFactoryOptions} config Validator config (custom to each
|
|
73
|
+
* validator)
|
|
72
74
|
*/
|
|
73
75
|
constructor(config = {}) {
|
|
74
76
|
if (new.target === ValidatorFactory) {
|
|
75
|
-
throw new TypeError(
|
|
77
|
+
throw new TypeError(
|
|
78
|
+
"Cannot instantiate the abstract class, ValidatorFactory",
|
|
79
|
+
);
|
|
76
80
|
}
|
|
77
81
|
this.config = config;
|
|
78
82
|
}
|
|
@@ -89,7 +93,7 @@ export default class ValidatorFactory {
|
|
|
89
93
|
* @throws {Error}
|
|
90
94
|
*/
|
|
91
95
|
validate(fieldValue, context) {
|
|
92
|
-
throw new Error(
|
|
96
|
+
throw new Error("validate() method has not been implemented");
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
/* eslint-disable-next-line jsdoc/require-returns-check */
|
|
@@ -1,43 +1,46 @@
|
|
|
1
1
|
/* eslint-disable sonarjs/no-duplicate-string */
|
|
2
|
-
import bytes from
|
|
3
|
-
import { PageField } from
|
|
4
|
-
import Plan from
|
|
5
|
-
import logger from
|
|
2
|
+
import bytes from "bytes";
|
|
3
|
+
import { PageField } from "./field.js";
|
|
4
|
+
import Plan from "./Plan.js";
|
|
5
|
+
import logger from "./logger.js";
|
|
6
6
|
import {
|
|
7
7
|
validateWaypoint,
|
|
8
8
|
validateHookName,
|
|
9
9
|
validateHookPath,
|
|
10
10
|
validateView,
|
|
11
|
-
} from
|
|
12
|
-
import * as contextIdGenerators from
|
|
13
|
-
import {
|
|
11
|
+
} from "./utils.js";
|
|
12
|
+
import * as contextIdGenerators from "./context-id-generators.js";
|
|
13
|
+
import {
|
|
14
|
+
CONFIG_ERROR_VISIBILITY_ALWAYS,
|
|
15
|
+
CONFIG_ERROR_VISIBILITY_ONSUBMIT,
|
|
16
|
+
} from "./constants.js";
|
|
14
17
|
|
|
15
18
|
/**
|
|
19
|
+
* @typedef {import("../casa").ConfigurationOptions} ConfigurationOptions
|
|
16
20
|
* @access private
|
|
17
|
-
* @typedef {import('../casa').ConfigurationOptions} ConfigurationOptions
|
|
18
21
|
*/
|
|
19
22
|
|
|
20
23
|
/**
|
|
24
|
+
* @typedef {import("../casa").HelmetConfigurator} HelmetConfigurator
|
|
21
25
|
* @access private
|
|
22
|
-
* @typedef {import('../casa').HelmetConfigurator} HelmetConfigurator
|
|
23
26
|
*/
|
|
24
27
|
|
|
25
|
-
const log = logger(
|
|
28
|
+
const log = logger("lib:configuration-ingestor");
|
|
26
29
|
|
|
27
|
-
const echo = (a) =>
|
|
30
|
+
const echo = (a) => a;
|
|
28
31
|
|
|
29
32
|
/**
|
|
30
33
|
* Validates and sanitises i18n object.
|
|
31
34
|
*
|
|
32
|
-
* @access private
|
|
33
35
|
* @param {object} i18n Object to validate.
|
|
34
36
|
* @param {Function} cb Callback function that receives the validated value.
|
|
35
|
-
* @throws {TypeError} For invalid object.
|
|
36
37
|
* @returns {object} Sanitised i18n object.
|
|
38
|
+
* @throws {TypeError} For invalid object.
|
|
39
|
+
* @access private
|
|
37
40
|
*/
|
|
38
41
|
export function validateI18nObject(i18n = Object.create(null), cb = echo) {
|
|
39
|
-
if (Object.prototype.toString.call(i18n) !==
|
|
40
|
-
throw new TypeError(
|
|
42
|
+
if (Object.prototype.toString.call(i18n) !== "[object Object]") {
|
|
43
|
+
throw new TypeError("I18n must be an object");
|
|
41
44
|
}
|
|
42
45
|
return cb(i18n);
|
|
43
46
|
}
|
|
@@ -45,19 +48,21 @@ export function validateI18nObject(i18n = Object.create(null), cb = echo) {
|
|
|
45
48
|
/**
|
|
46
49
|
* Validates and sanitises i18n directory.
|
|
47
50
|
*
|
|
48
|
-
* @access private
|
|
49
51
|
* @param {Array} dirs Array of directories.
|
|
52
|
+
* @returns {Array} Array of directories.
|
|
50
53
|
* @throws {SyntaxError} For invalid directories.
|
|
51
54
|
* @throws {TypeError} For invalid type.
|
|
52
|
-
* @
|
|
55
|
+
* @access private
|
|
53
56
|
*/
|
|
54
57
|
export function validateI18nDirs(dirs = []) {
|
|
55
58
|
if (!Array.isArray(dirs)) {
|
|
56
|
-
throw new TypeError(
|
|
59
|
+
throw new TypeError("I18n directories must be an array (i18n.dirs)");
|
|
57
60
|
}
|
|
58
61
|
dirs.forEach((dir, i) => {
|
|
59
|
-
if (typeof dir !==
|
|
60
|
-
throw new TypeError(
|
|
62
|
+
if (typeof dir !== "string") {
|
|
63
|
+
throw new TypeError(
|
|
64
|
+
`I18n directory must be a string, got ${typeof dir} (i18n.dirs[${i}])`,
|
|
65
|
+
);
|
|
61
66
|
}
|
|
62
67
|
});
|
|
63
68
|
return dirs;
|
|
@@ -66,19 +71,21 @@ export function validateI18nDirs(dirs = []) {
|
|
|
66
71
|
/**
|
|
67
72
|
* Validates and sanitises i18n locales.
|
|
68
73
|
*
|
|
69
|
-
* @access private
|
|
70
74
|
* @param {Array} locales Array of locales.
|
|
75
|
+
* @returns {Array} Array of locales.
|
|
71
76
|
* @throws {SyntaxError} For invalid locales.
|
|
72
77
|
* @throws {TypeError} For invalid type.
|
|
73
|
-
* @
|
|
78
|
+
* @access private
|
|
74
79
|
*/
|
|
75
|
-
export function validateI18nLocales(locales = [
|
|
80
|
+
export function validateI18nLocales(locales = ["en", "cy"]) {
|
|
76
81
|
if (!Array.isArray(locales)) {
|
|
77
|
-
throw new TypeError(
|
|
82
|
+
throw new TypeError("I18n locales must be an array (i18n.locales)");
|
|
78
83
|
}
|
|
79
84
|
locales.forEach((locale, i) => {
|
|
80
|
-
if (typeof locale !==
|
|
81
|
-
throw new TypeError(
|
|
85
|
+
if (typeof locale !== "string") {
|
|
86
|
+
throw new TypeError(
|
|
87
|
+
`I18n locale must be a string, got ${typeof locale} (i18n.locales[${i}])`,
|
|
88
|
+
);
|
|
82
89
|
}
|
|
83
90
|
});
|
|
84
91
|
return locales;
|
|
@@ -87,17 +94,17 @@ export function validateI18nLocales(locales = ['en', 'cy']) {
|
|
|
87
94
|
/**
|
|
88
95
|
* Validates and sanitises mount url.
|
|
89
96
|
*
|
|
90
|
-
* @access private
|
|
91
97
|
* @param {string} mountUrl Prefix for all URLs in the browser address bar
|
|
98
|
+
* @returns {string | undefined} Sanitised URL.
|
|
92
99
|
* @throws {SyntaxError} For invalid URL.
|
|
93
|
-
* @
|
|
100
|
+
* @access private
|
|
94
101
|
*/
|
|
95
102
|
export function validateMountUrl(mountUrl) {
|
|
96
|
-
if (typeof mountUrl ===
|
|
103
|
+
if (typeof mountUrl === "undefined") {
|
|
97
104
|
return undefined;
|
|
98
105
|
}
|
|
99
106
|
if (!mountUrl.match(/\/$/)) {
|
|
100
|
-
throw new SyntaxError(
|
|
107
|
+
throw new SyntaxError("mountUrl must include a trailing slash (/)");
|
|
101
108
|
}
|
|
102
109
|
return mountUrl;
|
|
103
110
|
}
|
|
@@ -105,19 +112,22 @@ export function validateMountUrl(mountUrl) {
|
|
|
105
112
|
/**
|
|
106
113
|
* Validates and sanitises sessions object.
|
|
107
114
|
*
|
|
108
|
-
* @access private
|
|
109
115
|
* @param {object} session Object to validate.
|
|
110
116
|
* @param {Function} cb Callback function that receives the validated value.
|
|
111
|
-
* @throws {TypeError} For invalid object.
|
|
112
117
|
* @returns {object} Sanitised sessions object.
|
|
118
|
+
* @throws {TypeError} For invalid object.
|
|
119
|
+
* @access private
|
|
113
120
|
*/
|
|
114
|
-
export function validateSessionObject(
|
|
121
|
+
export function validateSessionObject(
|
|
122
|
+
session = Object.create(null),
|
|
123
|
+
cb = echo,
|
|
124
|
+
) {
|
|
115
125
|
if (session === undefined) {
|
|
116
126
|
return cb(session);
|
|
117
127
|
}
|
|
118
128
|
|
|
119
|
-
if (typeof session !==
|
|
120
|
-
throw new TypeError(
|
|
129
|
+
if (typeof session !== "object") {
|
|
130
|
+
throw new TypeError("Session config has not been specified");
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
return cb(session);
|
|
@@ -126,19 +136,21 @@ export function validateSessionObject(session = Object.create(null), cb = echo)
|
|
|
126
136
|
/**
|
|
127
137
|
* Validates and sanitises view directory.
|
|
128
138
|
*
|
|
129
|
-
* @access private
|
|
130
139
|
* @param {Array} dirs Array of directories.
|
|
140
|
+
* @returns {Array} Array of directories.
|
|
131
141
|
* @throws {SyntaxError} For invalid directories.
|
|
132
142
|
* @throws {TypeError} For invalid type.
|
|
133
|
-
* @
|
|
143
|
+
* @access private
|
|
134
144
|
*/
|
|
135
145
|
export function validateViews(dirs = []) {
|
|
136
146
|
if (!Array.isArray(dirs)) {
|
|
137
|
-
throw new TypeError(
|
|
147
|
+
throw new TypeError("View directories must be an array (views)");
|
|
138
148
|
}
|
|
139
149
|
dirs.forEach((dir, i) => {
|
|
140
|
-
if (typeof dir !==
|
|
141
|
-
throw new TypeError(
|
|
150
|
+
if (typeof dir !== "string") {
|
|
151
|
+
throw new TypeError(
|
|
152
|
+
`View directory must be a string, got ${typeof dir} (views[${i}])`,
|
|
153
|
+
);
|
|
142
154
|
}
|
|
143
155
|
});
|
|
144
156
|
return dirs;
|
|
@@ -147,17 +159,17 @@ export function validateViews(dirs = []) {
|
|
|
147
159
|
/**
|
|
148
160
|
* Validates and sanitises sessions secret.
|
|
149
161
|
*
|
|
150
|
-
* @access private
|
|
151
162
|
* @param {string} secret Session secret.
|
|
163
|
+
* @returns {string} Secret.
|
|
152
164
|
* @throws {ReferenceError} For missing value type.
|
|
153
165
|
* @throws {TypeError} For invalid value.
|
|
154
|
-
* @
|
|
166
|
+
* @access private
|
|
155
167
|
*/
|
|
156
168
|
export function validateSessionSecret(secret) {
|
|
157
|
-
if (typeof secret ===
|
|
158
|
-
throw ReferenceError(
|
|
159
|
-
} else if (typeof secret !==
|
|
160
|
-
throw new TypeError(
|
|
169
|
+
if (typeof secret === "undefined") {
|
|
170
|
+
throw ReferenceError("Session secret is missing (session.secret)");
|
|
171
|
+
} else if (typeof secret !== "string") {
|
|
172
|
+
throw new TypeError("Session secret must be a string (session.secret)");
|
|
161
173
|
}
|
|
162
174
|
return secret;
|
|
163
175
|
}
|
|
@@ -165,15 +177,15 @@ export function validateSessionSecret(secret) {
|
|
|
165
177
|
/**
|
|
166
178
|
* Validates and sanitises sessions ttl.
|
|
167
179
|
*
|
|
168
|
-
* @access private
|
|
169
180
|
* @param {number} ttl Session ttl (seconds).
|
|
181
|
+
* @returns {number} Ttl.
|
|
170
182
|
* @throws {ReferenceError} For missing value type.
|
|
171
183
|
* @throws {TypeError} For invalid value.
|
|
172
|
-
* @
|
|
184
|
+
* @access private
|
|
173
185
|
*/
|
|
174
186
|
export function validateSessionTtl(ttl = 3600) {
|
|
175
|
-
if (typeof ttl !==
|
|
176
|
-
throw new TypeError(
|
|
187
|
+
if (typeof ttl !== "number") {
|
|
188
|
+
throw new TypeError("Session ttl must be an integer (session.ttl)");
|
|
177
189
|
}
|
|
178
190
|
return ttl;
|
|
179
191
|
}
|
|
@@ -181,15 +193,15 @@ export function validateSessionTtl(ttl = 3600) {
|
|
|
181
193
|
/**
|
|
182
194
|
* Validates and sanitises sessions name.
|
|
183
195
|
*
|
|
184
|
-
* @
|
|
185
|
-
* @
|
|
196
|
+
* @param {string} [name=casa-session] Session name. Default is `casa-session`
|
|
197
|
+
* @returns {string} Name.
|
|
186
198
|
* @throws {ReferenceError} For missing value type.
|
|
187
199
|
* @throws {TypeError} For invalid value.
|
|
188
|
-
* @
|
|
200
|
+
* @access private
|
|
189
201
|
*/
|
|
190
|
-
export function validateSessionName(name =
|
|
191
|
-
if (typeof name !==
|
|
192
|
-
throw new TypeError(
|
|
202
|
+
export function validateSessionName(name = "casa-session") {
|
|
203
|
+
if (typeof name !== "string") {
|
|
204
|
+
throw new TypeError("Session name must be a string (session.name)");
|
|
193
205
|
}
|
|
194
206
|
return name;
|
|
195
207
|
}
|
|
@@ -197,18 +209,20 @@ export function validateSessionName(name = 'casa-session') {
|
|
|
197
209
|
/**
|
|
198
210
|
* Validates and sanitises sessions secure flag.
|
|
199
211
|
*
|
|
200
|
-
* @access private
|
|
201
212
|
* @param {boolean} [secure] Session secure flag.
|
|
213
|
+
* @returns {string} Name.
|
|
202
214
|
* @throws {ReferenceError} For missing value type.
|
|
203
215
|
* @throws {TypeError} For invalid or missing value.
|
|
204
|
-
* @
|
|
216
|
+
* @access private
|
|
205
217
|
*/
|
|
206
218
|
export function validateSessionSecure(secure) {
|
|
207
219
|
if (secure === undefined) {
|
|
208
|
-
throw new Error(
|
|
220
|
+
throw new Error(
|
|
221
|
+
"Session secure flag must be explicitly defined (session.secure)",
|
|
222
|
+
);
|
|
209
223
|
}
|
|
210
|
-
if (typeof secure !==
|
|
211
|
-
throw new TypeError(
|
|
224
|
+
if (typeof secure !== "boolean") {
|
|
225
|
+
throw new TypeError("Session secure flag must be boolean (session.secure)");
|
|
212
226
|
}
|
|
213
227
|
return secure;
|
|
214
228
|
}
|
|
@@ -216,13 +230,15 @@ export function validateSessionSecure(secure) {
|
|
|
216
230
|
/**
|
|
217
231
|
* Validates and sanitises sessions store.
|
|
218
232
|
*
|
|
219
|
-
* @access private
|
|
220
233
|
* @param {Function} store Session store.
|
|
221
234
|
* @returns {Function} Store.
|
|
235
|
+
* @access private
|
|
222
236
|
*/
|
|
223
237
|
export function validateSessionStore(store) {
|
|
224
|
-
if (typeof store ===
|
|
225
|
-
log.warn(
|
|
238
|
+
if (typeof store === "undefined") {
|
|
239
|
+
log.warn(
|
|
240
|
+
"Using MemoryStore session storage, which is not suitable for production",
|
|
241
|
+
);
|
|
226
242
|
return null;
|
|
227
243
|
}
|
|
228
244
|
return store;
|
|
@@ -231,63 +247,74 @@ export function validateSessionStore(store) {
|
|
|
231
247
|
/**
|
|
232
248
|
* Validates and sanitises sessions cookie url path.
|
|
233
249
|
*
|
|
234
|
-
* @access private
|
|
235
250
|
* @param {string} cookiePath Session cookie url path.
|
|
236
251
|
* @param {string} defaultPath Default path if none specified.
|
|
237
252
|
* @returns {string} Cookie path.
|
|
253
|
+
* @access private
|
|
238
254
|
*/
|
|
239
|
-
export function validateSessionCookiePath(cookiePath, defaultPath =
|
|
240
|
-
if (typeof cookiePath ===
|
|
255
|
+
export function validateSessionCookiePath(cookiePath, defaultPath = "/") {
|
|
256
|
+
if (typeof cookiePath === "undefined") {
|
|
241
257
|
return defaultPath;
|
|
242
258
|
}
|
|
243
259
|
return cookiePath;
|
|
244
260
|
}
|
|
245
261
|
|
|
246
262
|
/**
|
|
247
|
-
* Validates and sanitises sessions cookie "sameSite" flag. One of:
|
|
248
|
-
*
|
|
249
|
-
* false (will not set the flag at all)
|
|
250
|
-
* Strict
|
|
251
|
-
* Lax
|
|
252
|
-
* None
|
|
263
|
+
* Validates and sanitises sessions cookie "sameSite" flag. One of: true
|
|
264
|
+
* (Strict) false (will not set the flag at all) Strict Lax None
|
|
253
265
|
*
|
|
254
|
-
* @access private
|
|
255
266
|
* @param {any} cookieSameSite Session cookie "sameSite" flag
|
|
256
267
|
* @param {any} defaultFlag Default path if none specified
|
|
257
|
-
* @returns {boolean}
|
|
268
|
+
* @returns {boolean} Cookie path
|
|
258
269
|
* @throws {TypeError} When invalid arguments are provided
|
|
270
|
+
* @access private
|
|
259
271
|
*/
|
|
260
272
|
|
|
261
273
|
/**
|
|
262
274
|
* Validates errorVisibility.
|
|
263
275
|
*
|
|
264
|
-
* @
|
|
265
|
-
*
|
|
276
|
+
* @param {string} errorVisibility Sets visibility flag for page validation
|
|
277
|
+
* error
|
|
278
|
+
* @returns {symbol | Function} Flag for error visibility.
|
|
266
279
|
* @throws {SyntaxError} For invalid errorVisibility flag.
|
|
267
|
-
* @
|
|
280
|
+
* @access private
|
|
268
281
|
*/
|
|
269
|
-
export function validateErrorVisibility(
|
|
282
|
+
export function validateErrorVisibility(
|
|
283
|
+
errorVisibility = CONFIG_ERROR_VISIBILITY_ONSUBMIT,
|
|
284
|
+
) {
|
|
270
285
|
if (errorVisibility === undefined) {
|
|
271
286
|
return undefined;
|
|
272
287
|
}
|
|
273
|
-
if (
|
|
288
|
+
if (
|
|
289
|
+
errorVisibility === CONFIG_ERROR_VISIBILITY_ALWAYS ||
|
|
290
|
+
errorVisibility === CONFIG_ERROR_VISIBILITY_ONSUBMIT ||
|
|
291
|
+
typeof errorVisibility === "function"
|
|
292
|
+
) {
|
|
274
293
|
return errorVisibility;
|
|
275
294
|
}
|
|
276
|
-
throw new TypeError(
|
|
295
|
+
throw new TypeError(
|
|
296
|
+
"errorVisibility must be casa constant CONFIG_ERROR_VISIBILITY_ALWAYS | CONFIG_ERROR_VISIBILITY_ONSUBMIT or function",
|
|
297
|
+
);
|
|
277
298
|
}
|
|
278
299
|
|
|
279
300
|
export function validateSessionCookieSameSite(cookieSameSite, defaultFlag) {
|
|
280
|
-
const validValues = [true, false,
|
|
301
|
+
const validValues = [true, false, "Strict", "Lax", "None"];
|
|
281
302
|
|
|
282
303
|
if (defaultFlag === undefined) {
|
|
283
|
-
throw new TypeError(
|
|
304
|
+
throw new TypeError(
|
|
305
|
+
"validateSessionCookieSameSite() requires an explicit default flag",
|
|
306
|
+
);
|
|
284
307
|
} else if (!validValues.includes(defaultFlag)) {
|
|
285
|
-
throw new TypeError(
|
|
308
|
+
throw new TypeError(
|
|
309
|
+
"validateSessionCookieSameSite() default flag must be set to one of true, false, Strict, Lax or None (session.cookieSameSite)",
|
|
310
|
+
);
|
|
286
311
|
}
|
|
287
312
|
|
|
288
313
|
const value = cookieSameSite !== undefined ? cookieSameSite : defaultFlag;
|
|
289
314
|
if (!validValues.includes(value)) {
|
|
290
|
-
throw new TypeError(
|
|
315
|
+
throw new TypeError(
|
|
316
|
+
"SameSite flag must be set to one of true, false, Strict, Lax or None (session.cookieSameSite)",
|
|
317
|
+
);
|
|
291
318
|
}
|
|
292
319
|
|
|
293
320
|
return value;
|
|
@@ -296,18 +323,18 @@ export function validateSessionCookieSameSite(cookieSameSite, defaultFlag) {
|
|
|
296
323
|
const validatePageHook = (hook, index) => {
|
|
297
324
|
try {
|
|
298
325
|
validateHookName(hook.hook);
|
|
299
|
-
if (typeof hook.middleware !==
|
|
300
|
-
throw new TypeError(
|
|
326
|
+
if (typeof hook.middleware !== "function") {
|
|
327
|
+
throw new TypeError("Hook middleware must be a function");
|
|
301
328
|
}
|
|
302
329
|
} catch (err) {
|
|
303
330
|
err.message = `Page hook at index ${index} is invalid: ${err.message}`;
|
|
304
331
|
throw err;
|
|
305
332
|
}
|
|
306
|
-
}
|
|
333
|
+
};
|
|
307
334
|
|
|
308
335
|
export function validatePageHooks(hooks) {
|
|
309
336
|
if (!Array.isArray(hooks)) {
|
|
310
|
-
throw new TypeError(
|
|
337
|
+
throw new TypeError("Hooks must be an array");
|
|
311
338
|
}
|
|
312
339
|
hooks.forEach((hook, index) => validatePageHook(hook, index));
|
|
313
340
|
return hooks;
|
|
@@ -316,7 +343,9 @@ export function validatePageHooks(hooks) {
|
|
|
316
343
|
const validateField = (field, index) => {
|
|
317
344
|
try {
|
|
318
345
|
if (!(field instanceof PageField)) {
|
|
319
|
-
throw new TypeError(
|
|
346
|
+
throw new TypeError(
|
|
347
|
+
'Page field must be an instance of PageField (created via the "field()" function)',
|
|
348
|
+
);
|
|
320
349
|
}
|
|
321
350
|
} catch (err) {
|
|
322
351
|
err.message = `Page field at index ${index} is invalid: ${err.message}`;
|
|
@@ -326,7 +355,7 @@ const validateField = (field, index) => {
|
|
|
326
355
|
|
|
327
356
|
export function validateFields(fields) {
|
|
328
357
|
if (!Array.isArray(fields)) {
|
|
329
|
-
throw new TypeError(
|
|
358
|
+
throw new TypeError("Page fields must be an array (page[].fields)");
|
|
330
359
|
}
|
|
331
360
|
fields.forEach((hook, index) => validateField(hook, index));
|
|
332
361
|
return fields;
|
|
@@ -343,17 +372,17 @@ const validatePage = (page, index) => {
|
|
|
343
372
|
validatePageHooks(page.hooks);
|
|
344
373
|
}
|
|
345
374
|
if (page.errorVisibility !== undefined) {
|
|
346
|
-
validateErrorVisibility(page.errorVisibility)
|
|
375
|
+
validateErrorVisibility(page.errorVisibility);
|
|
347
376
|
}
|
|
348
377
|
} catch (err) {
|
|
349
378
|
err.message = `Page at index ${index} is invalid: ${err.message}`;
|
|
350
379
|
throw err;
|
|
351
380
|
}
|
|
352
|
-
}
|
|
381
|
+
};
|
|
353
382
|
|
|
354
383
|
export function validatePages(pages = []) {
|
|
355
384
|
if (!Array.isArray(pages)) {
|
|
356
|
-
throw new TypeError(
|
|
385
|
+
throw new TypeError("Pages must be an array (pages)");
|
|
357
386
|
}
|
|
358
387
|
pages.forEach((page, index) => validatePage(page, index));
|
|
359
388
|
return pages;
|
|
@@ -365,7 +394,7 @@ export function validatePlan(plan) {
|
|
|
365
394
|
}
|
|
366
395
|
|
|
367
396
|
if (!(plan instanceof Plan)) {
|
|
368
|
-
throw new TypeError(
|
|
397
|
+
throw new TypeError("Plan must be an instance the Plan class (plan)");
|
|
369
398
|
}
|
|
370
399
|
|
|
371
400
|
return plan;
|
|
@@ -374,8 +403,8 @@ export function validatePlan(plan) {
|
|
|
374
403
|
const validateGlobalHook = (hook, index) => {
|
|
375
404
|
try {
|
|
376
405
|
validateHookName(hook.hook);
|
|
377
|
-
if (typeof hook.middleware !==
|
|
378
|
-
throw new TypeError(
|
|
406
|
+
if (typeof hook.middleware !== "function") {
|
|
407
|
+
throw new TypeError("Hook middleware must be a function");
|
|
379
408
|
}
|
|
380
409
|
if (hook.path !== undefined) {
|
|
381
410
|
validateHookPath(hook.path);
|
|
@@ -392,7 +421,7 @@ export function validateGlobalHooks(hooks) {
|
|
|
392
421
|
}
|
|
393
422
|
|
|
394
423
|
if (!Array.isArray(hooks)) {
|
|
395
|
-
throw new TypeError(
|
|
424
|
+
throw new TypeError("Hooks must be an array");
|
|
396
425
|
}
|
|
397
426
|
|
|
398
427
|
hooks.forEach((hook, index) => validateGlobalHook(hook, index));
|
|
@@ -410,14 +439,17 @@ export function validateEvents(events) {
|
|
|
410
439
|
/**
|
|
411
440
|
* Validates helmet configuration function.
|
|
412
441
|
*
|
|
413
|
-
* @access private
|
|
414
442
|
* @param {HelmetConfigurator} helmetConfigurator Configuration function
|
|
415
443
|
* @returns {HelmetConfigurator} Validated configuration function
|
|
416
|
-
* @throws {TypeError}
|
|
444
|
+
* @throws {TypeError} When passed a non-function
|
|
445
|
+
* @access private
|
|
417
446
|
*/
|
|
418
447
|
export function validateHelmetConfigurator(helmetConfigurator) {
|
|
419
|
-
if (
|
|
420
|
-
|
|
448
|
+
if (
|
|
449
|
+
helmetConfigurator !== undefined &&
|
|
450
|
+
!(helmetConfigurator instanceof Function)
|
|
451
|
+
) {
|
|
452
|
+
throw new TypeError("Helmet configurator must be a function");
|
|
421
453
|
}
|
|
422
454
|
|
|
423
455
|
return helmetConfigurator;
|
|
@@ -432,7 +464,7 @@ export function validateFormMaxParams(value, defaultValue = 25) {
|
|
|
432
464
|
return defaultValue;
|
|
433
465
|
}
|
|
434
466
|
if (!Number.isInteger(value)) {
|
|
435
|
-
throw new TypeError(
|
|
467
|
+
throw new TypeError("formMaxParams must be an integer");
|
|
436
468
|
}
|
|
437
469
|
if (value < MIN_PARAMS) {
|
|
438
470
|
throw new RangeError(`formMaxParams must be at least ${MIN_PARAMS}`);
|
|
@@ -450,10 +482,12 @@ export function validateFormMaxBytes(value, defaultValue = 1024 * 50) {
|
|
|
450
482
|
|
|
451
483
|
const parsedValue = bytes.parse(value);
|
|
452
484
|
if (!Number.isInteger(parsedValue)) {
|
|
453
|
-
throw new TypeError(
|
|
485
|
+
throw new TypeError("formMaxParams must be a string or an integer");
|
|
454
486
|
}
|
|
455
487
|
if (parsedValue < MIN_BYTES) {
|
|
456
|
-
throw new RangeError(
|
|
488
|
+
throw new RangeError(
|
|
489
|
+
`formMaxBytes must be at least ${MIN_BYTES} bytes (${bytes.format(MIN_BYTES)})`,
|
|
490
|
+
);
|
|
457
491
|
}
|
|
458
492
|
|
|
459
493
|
return parsedValue;
|
|
@@ -465,7 +499,7 @@ export function validateContextIdGenerator(generator) {
|
|
|
465
499
|
}
|
|
466
500
|
|
|
467
501
|
if (!(generator instanceof Function)) {
|
|
468
|
-
throw new TypeError(
|
|
502
|
+
throw new TypeError("contextIdGenerator must be a function");
|
|
469
503
|
}
|
|
470
504
|
|
|
471
505
|
return generator;
|
|
@@ -474,10 +508,10 @@ export function validateContextIdGenerator(generator) {
|
|
|
474
508
|
/**
|
|
475
509
|
* Ingest, validate, sanitise and manipulate configuration parameters.
|
|
476
510
|
*
|
|
477
|
-
* @access private
|
|
478
511
|
* @param {ConfigurationOptions} config Config to ingest.
|
|
479
|
-
* @throws {Error|SyntaxError|TypeError} For invalid config values.
|
|
480
512
|
* @returns {object} Immutable config object.
|
|
513
|
+
* @throws {Error | SyntaxError | TypeError} For invalid config values.
|
|
514
|
+
* @access private
|
|
481
515
|
*/
|
|
482
516
|
export default function ingest(config = {}) {
|
|
483
517
|
const parsed = {
|
|
@@ -500,8 +534,11 @@ export default function ingest(config = {}) {
|
|
|
500
534
|
secure: validateSessionSecure(session.secure),
|
|
501
535
|
ttl: validateSessionTtl(session.ttl),
|
|
502
536
|
store: validateSessionStore(session.store),
|
|
503
|
-
cookiePath: validateSessionCookiePath(session.cookiePath,
|
|
504
|
-
cookieSameSite: validateSessionCookieSameSite(
|
|
537
|
+
cookiePath: validateSessionCookiePath(session.cookiePath, "/"),
|
|
538
|
+
cookieSameSite: validateSessionCookieSameSite(
|
|
539
|
+
session.cookieSameSite,
|
|
540
|
+
"Strict",
|
|
541
|
+
),
|
|
505
542
|
})),
|
|
506
543
|
|
|
507
544
|
// Views configuration
|