@dwp/govuk-casa 8.0.0-beta2 → 8.0.3

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 (41) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/dist/assets/css/casa-ie8.css +1 -1
  4. package/dist/assets/css/casa.css +1 -1
  5. package/dist/lib/CasaTemplateLoader.d.ts +1 -3
  6. package/dist/lib/CasaTemplateLoader.js +22 -3
  7. package/dist/lib/JourneyContext.d.ts +1 -0
  8. package/dist/lib/JourneyContext.js +37 -11
  9. package/dist/lib/MutableRouter.js +3 -1
  10. package/dist/lib/Plan.js +12 -5
  11. package/dist/lib/ValidationError.js +4 -0
  12. package/dist/lib/configuration-ingestor.js +11 -37
  13. package/dist/lib/configure.js +1 -2
  14. package/dist/lib/dirname.cjs +1 -1
  15. package/dist/lib/end-session.js +4 -1
  16. package/dist/lib/field.d.ts +2 -2
  17. package/dist/lib/field.js +19 -2
  18. package/dist/lib/logger.d.ts +1 -1
  19. package/dist/lib/logger.js +2 -2
  20. package/dist/lib/nunjucks-filters.js +8 -0
  21. package/dist/lib/utils.js +2 -0
  22. package/dist/lib/validators/inArray.js +1 -1
  23. package/dist/lib/validators/index.js +0 -22
  24. package/dist/lib/validators/postalAddressObject.js +6 -2
  25. package/dist/middleware/body-parser.d.ts +1 -0
  26. package/dist/middleware/body-parser.js +18 -9
  27. package/dist/middleware/data.js +8 -4
  28. package/dist/middleware/dirname.cjs +1 -1
  29. package/dist/middleware/gather-fields.js +3 -5
  30. package/dist/middleware/i18n.js +5 -1
  31. package/dist/middleware/post.js +1 -1
  32. package/dist/middleware/pre.js +10 -2
  33. package/dist/middleware/progress-journey.js +1 -1
  34. package/dist/middleware/sanitise-fields.js +5 -5
  35. package/dist/middleware/session.js +60 -53
  36. package/dist/middleware/skip-waypoint.js +2 -2
  37. package/dist/middleware/validate-fields.js +7 -6
  38. package/dist/routes/ancillary.js +0 -2
  39. package/dist/routes/dirname.cjs +1 -1
  40. package/dist/routes/journey.js +5 -6
  41. package/package.json +37 -30
@@ -26,6 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  };
27
27
  var _JourneyContext_data, _JourneyContext_validation, _JourneyContext_nav, _JourneyContext_identity, _JourneyContext_eventListeners, _JourneyContext_eventListenerPreState;
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.validateObjectKey = void 0;
29
30
  /**
30
31
  * Represents the state of a user's journey through the Plan. It contains
31
32
  * information about:
@@ -39,7 +40,7 @@ const lodash_1 = __importDefault(require("lodash"));
39
40
  const ValidationError_js_1 = __importDefault(require("./ValidationError.js"));
40
41
  const logger_js_1 = __importDefault(require("./logger.js"));
41
42
  const { cloneDeep, isPlainObject, isObject, has, isEqual, } = lodash_1.default; // CommonJS
42
- const log = (0, logger_js_1.default)('class:journey-context');
43
+ const log = (0, logger_js_1.default)('lib:journey-context');
43
44
  /**
44
45
  * @typedef {import('./configuration-ingestor').Page} Page
45
46
  */
@@ -55,6 +56,14 @@ const log = (0, logger_js_1.default)('class:journey-context');
55
56
  * @property {string} [field] Field to watch for changes
56
57
  * @property {ContextEventHandler} handler Handler to invoke when change happens
57
58
  */
59
+ function validateObjectKey(key = '') {
60
+ const keyLower = String.prototype.toLowerCase.call(key);
61
+ if (keyLower === 'prototype' || keyLower === '__proto__' || keyLower === 'constructor') {
62
+ throw new SyntaxError(`Invalid object key used, ${key}`);
63
+ }
64
+ return String(key);
65
+ }
66
+ exports.validateObjectKey = validateObjectKey;
58
67
  class JourneyContext {
59
68
  /**
60
69
  * Constructor.
@@ -144,10 +153,10 @@ class JourneyContext {
144
153
  */
145
154
  getDataForPage(page) {
146
155
  if (typeof page === 'string') {
147
- return __classPrivateFieldGet(this, _JourneyContext_data, "f")[page];
156
+ return __classPrivateFieldGet(this, _JourneyContext_data, "f")[validateObjectKey(page)];
148
157
  }
149
158
  if (isPlainObject(page)) {
150
- return __classPrivateFieldGet(this, _JourneyContext_data, "f")[page.waypoint];
159
+ return __classPrivateFieldGet(this, _JourneyContext_data, "f")[validateObjectKey(page.waypoint)];
151
160
  }
152
161
  throw new TypeError(`Page must be a string or Page object. Got ${typeof page}`);
153
162
  }
@@ -179,10 +188,10 @@ class JourneyContext {
179
188
  */
180
189
  setDataForPage(page, webFormData) {
181
190
  if (typeof page === 'string') {
182
- __classPrivateFieldGet(this, _JourneyContext_data, "f")[page] = webFormData;
191
+ __classPrivateFieldGet(this, _JourneyContext_data, "f")[validateObjectKey(page)] = webFormData;
183
192
  }
184
193
  else if (isPlainObject(page)) {
185
- __classPrivateFieldGet(this, _JourneyContext_data, "f")[page.waypoint] = webFormData;
194
+ __classPrivateFieldGet(this, _JourneyContext_data, "f")[validateObjectKey(page.waypoint)] = webFormData;
186
195
  }
187
196
  else {
188
197
  throw new TypeError(`Page must be a string or Page object. Got ${typeof page}`);
@@ -220,7 +229,7 @@ class JourneyContext {
220
229
  * @returns {JourneyContext} Chain.
221
230
  */
222
231
  clearValidationErrorsForPage(pageId) {
223
- __classPrivateFieldGet(this, _JourneyContext_validation, "f")[pageId] = null;
232
+ __classPrivateFieldGet(this, _JourneyContext_validation, "f")[validateObjectKey(pageId)] = null;
224
233
  return this;
225
234
  }
226
235
  /**
@@ -240,7 +249,7 @@ class JourneyContext {
240
249
  throw new SyntaxError('Field errors must be a ValidationError');
241
250
  }
242
251
  });
243
- __classPrivateFieldGet(this, _JourneyContext_validation, "f")[pageId] = errors;
252
+ __classPrivateFieldGet(this, _JourneyContext_validation, "f")[validateObjectKey(pageId)] = errors;
244
253
  return this;
245
254
  }
246
255
  /**
@@ -251,17 +260,21 @@ class JourneyContext {
251
260
  * @returns {ValidationError[]} An array of errors
252
261
  */
253
262
  getValidationErrorsForPage(pageId) {
254
- return __classPrivateFieldGet(this, _JourneyContext_validation, "f")[pageId] || [];
263
+ var _a;
264
+ return (_a = __classPrivateFieldGet(this, _JourneyContext_validation, "f")[validateObjectKey(pageId)]) !== null && _a !== void 0 ? _a : [];
255
265
  }
256
266
  getValidationErrorsForPageByField(pageId) {
257
267
  const errors = this.getValidationErrorsForPage(pageId);
258
268
  const obj = Object.create(null);
269
+ // ESLint disabled as `i` is an integer
270
+ /* eslint-disable security/detect-object-injection */
259
271
  for (let i = 0, l = errors.length; i < l; i++) {
260
272
  if (!obj[errors[i].field]) {
261
273
  obj[errors[i].field] = [];
262
274
  }
263
275
  obj[errors[i].field].push(errors[i]);
264
276
  }
277
+ /* eslint-enable security/detect-object-injection */
265
278
  return obj;
266
279
  }
267
280
  /**
@@ -273,7 +286,7 @@ class JourneyContext {
273
286
  */
274
287
  hasValidationErrorsForPage(pageId) {
275
288
  var _a, _b;
276
- return ((_b = (_a = __classPrivateFieldGet(this, _JourneyContext_validation, "f")) === null || _a === void 0 ? void 0 : _a[pageId]) === null || _b === void 0 ? void 0 : _b.length) > 0;
289
+ return ((_b = (_a = __classPrivateFieldGet(this, _JourneyContext_validation, "f")) === null || _a === void 0 ? void 0 : _a[validateObjectKey(pageId)]) === null || _b === void 0 ? void 0 : _b.length) > 0;
277
290
  }
278
291
  /**
279
292
  * Set language of the context.
@@ -292,7 +305,7 @@ class JourneyContext {
292
305
  * @returns {boolean} True if the page is valid.
293
306
  */
294
307
  isPageValid(pageId) {
295
- return __classPrivateFieldGet(this, _JourneyContext_validation, "f")[pageId] === null;
308
+ return __classPrivateFieldGet(this, _JourneyContext_validation, "f")[validateObjectKey(pageId)] === null;
296
309
  }
297
310
  /**
298
311
  * Remove information about these waypoints.
@@ -303,10 +316,13 @@ class JourneyContext {
303
316
  const newData = Object.create(null);
304
317
  const newValidation = Object.create(null);
305
318
  const toKeep = Object.keys(this.data).filter((w) => !waypoints.includes(w));
319
+ // ESLint disabled as `i` is an integer
320
+ /* eslint-disable security/detect-object-injection */
306
321
  for (let i = 0, l = toKeep.length; i < l; i++) {
307
322
  newData[toKeep[i]] = __classPrivateFieldGet(this, _JourneyContext_data, "f")[toKeep[i]];
308
323
  newValidation[toKeep[i]] = __classPrivateFieldGet(this, _JourneyContext_validation, "f")[toKeep[i]];
309
324
  }
325
+ /* eslint-enable security/detect-object-injection */
310
326
  __classPrivateFieldSet(this, _JourneyContext_data, Object.assign({}, newData), "f");
311
327
  __classPrivateFieldSet(this, _JourneyContext_validation, Object.assign({}, newValidation), "f");
312
328
  }
@@ -319,6 +335,8 @@ class JourneyContext {
319
335
  */
320
336
  invalidate(waypoints = []) {
321
337
  for (let i = 0, l = waypoints.length; i < l; i++) {
338
+ // ESLint disabled as `i` is an integer
339
+ /* eslint-disable-next-line security/detect-object-injection */
322
340
  this.removeValidationStateForPage(waypoints[i]);
323
341
  }
324
342
  }
@@ -346,6 +364,10 @@ class JourneyContext {
346
364
  }
347
365
  const previousContext = JourneyContext.fromObject(__classPrivateFieldGet(this, _JourneyContext_eventListenerPreState, "f"));
348
366
  const listeners = __classPrivateFieldGet(this, _JourneyContext_eventListeners, "f").filter((l) => l.event === event);
367
+ // ESLint disabled as `listeners[i]` uses an integer key, and the other keys
368
+ // are derived from the list of `listeners`, which are not manipulated at
369
+ // runtime (only set by dev in code).
370
+ /* eslint-disable security/detect-object-injection */
349
371
  for (let i = 0, l = listeners.length; i < l; i++) {
350
372
  const { waypoint, field, handler } = listeners[i];
351
373
  let logMessage;
@@ -367,6 +389,7 @@ class JourneyContext {
367
389
  handler({ journeyContext: this, previousContext });
368
390
  }
369
391
  }
392
+ /* eslint-enable security/detect-object-injection */
370
393
  return this;
371
394
  }
372
395
  /* ----------------------------------------------- session context handling */
@@ -440,6 +463,8 @@ class JourneyContext {
440
463
  */
441
464
  static getContextById(session, id) {
442
465
  if (has(session === null || session === void 0 ? void 0 : session.journeyContextList, id)) {
466
+ // ESLint disabled as `id` has been verified as an "own" property
467
+ /* eslint-disable-next-line security/detect-object-injection */
443
468
  return JourneyContext.fromObject(session.journeyContextList[id]);
444
469
  }
445
470
  return undefined;
@@ -533,7 +558,8 @@ class JourneyContext {
533
558
  }
534
559
  static removeContextById(session, id) {
535
560
  if (session && has(session.journeyContextList, id)) {
536
- /* eslint-disable-next-line no-param-reassign */
561
+ // ESLint disabled as `id` has been verified as an "own" property
562
+ /* eslint-disable-next-line security/detect-object-injection, no-param-reassign */
537
563
  delete session.journeyContextList[id];
538
564
  }
539
565
  }
@@ -48,6 +48,9 @@ class MutableRouter {
48
48
  return __classPrivateFieldGet(this, _MutableRouter_router, "f");
49
49
  }
50
50
  __classPrivateFieldGet(this, _MutableRouter_stack, "f").forEach(({ method, args }) => {
51
+ // ESLint disabled as `#router` is dev-controlled, and `seal()` is only
52
+ // run at boot-time before any user interaction
53
+ /* eslint-disable-next-line security/detect-object-injection */
51
54
  __classPrivateFieldGet(this, _MutableRouter_router, "f")[method].call(__classPrivateFieldGet(this, _MutableRouter_router, "f"), ...args);
52
55
  });
53
56
  __classPrivateFieldSet(this, _MutableRouter_sealed, true, "f");
@@ -115,7 +118,6 @@ class MutableRouter {
115
118
  __classPrivateFieldGet(this, _MutableRouter_instances, "m", _MutableRouter_prepend).call(this, 'use', path, ...callbacks);
116
119
  }
117
120
  /* -------------------------------------------------------------- replacers */
118
- // TODO: How do we handle multiple routes on the same path?
119
121
  /**
120
122
  * Replace middleware function(s) that were mounted using the `all()` method.
121
123
  *
package/dist/lib/Plan.js CHANGED
@@ -18,7 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const graphlib_1 = require("graphlib");
19
19
  const JourneyContext_js_1 = __importDefault(require("./JourneyContext.js"));
20
20
  const logger_js_1 = __importDefault(require("./logger.js"));
21
- const log = (0, logger_js_1.default)('class:plan');
21
+ const log = (0, logger_js_1.default)('lib:plan');
22
22
  /**
23
23
  * Will check if the source waypoint has specifically passed validation, i.e
24
24
  * there is a "null" validation entry for the route source.
@@ -58,6 +58,7 @@ function validateRouteName(val) {
58
58
  else if (!['next', 'prev'].includes(val)) {
59
59
  throw new ReferenceError(`Expected route name to be one of next or prev. Got ${val}`);
60
60
  }
61
+ return val;
61
62
  }
62
63
  function validateRouteCondition(val) {
63
64
  if (!(val instanceof Function)) {
@@ -177,7 +178,7 @@ class Plan {
177
178
  return self.dgraph.edges().map((edge) => makeRouteObject(self.dgraph, edge));
178
179
  }
179
180
  getRouteCondition(src, tgt, name) {
180
- return priv.get(this).follows[name][`${src}/${tgt}`];
181
+ return priv.get(this).follows[validateRouteName(name)][`${src}/${tgt}`];
181
182
  }
182
183
  /**
183
184
  * Return all outward routes (out-edges) from the given waypoint, to the
@@ -205,6 +206,8 @@ class Plan {
205
206
  addSequence(...waypoints) {
206
207
  // Setup simple double routes (next/prev) between all waypoints in this list
207
208
  for (let i = 0, l = waypoints.length - 1; i < l; i += 1) {
209
+ // ESLint disabled as `i` is an integer
210
+ /* eslint-disable-next-line security/detect-object-injection */
208
211
  this.setRoute(waypoints[i], waypoints[i + 1]);
209
212
  }
210
213
  }
@@ -309,6 +312,8 @@ class Plan {
309
312
  else {
310
313
  followFunc = defaultPrevFollow;
311
314
  }
315
+ // ESLint disabled as `name` has been validated further above
316
+ /* eslint-disable-next-line security/detect-object-injection */
312
317
  self.follows[name][`${src}/${tgt}`] = followFunc;
313
318
  return this;
314
319
  }
@@ -360,9 +365,7 @@ class Plan {
360
365
  if (!self.dgraph.hasNode(startWaypoint)) {
361
366
  throw new ReferenceError(`Plan does not contain waypoint '${startWaypoint}'`);
362
367
  }
363
- if (routeName === undefined) {
364
- throw new ReferenceError('Route name must be provided');
365
- }
368
+ validateRouteName(routeName);
366
369
  const history = new Map();
367
370
  const traverse = (startWP) => {
368
371
  let target = self.dgraph.outEdges(startWP).filter((e) => {
@@ -371,6 +374,8 @@ class Plan {
371
374
  }
372
375
  const route = makeRouteObject(self.dgraph, e);
373
376
  try {
377
+ // ESLint disabled as `routeName` has been validated further above
378
+ /* eslint-disable-next-line security/detect-object-injection */
374
379
  return self.follows[routeName][`${e.v}/${e.w}`](route, context);
375
380
  }
376
381
  catch (ex) {
@@ -413,6 +418,8 @@ class Plan {
413
418
  const results = new Array(totalTrav + 1);
414
419
  results[0] = route;
415
420
  for (let i = 0; i < totalTrav; i++) {
421
+ // ESLint disabled as `i` is an integer
422
+ /* eslint-disable-next-line security/detect-object-injection */
416
423
  results[i + 1] = traversed[i];
417
424
  }
418
425
  return results;
@@ -114,11 +114,15 @@ class ValidationError {
114
114
  // the values that will be readable, and reflect any context that may have
115
115
  // been applied
116
116
  Object.keys(originals).forEach((o) => {
117
+ // ESLint disabled as `o` is an "own" property of `originals`, which is
118
+ // dev-controlled
119
+ /* eslint-disable security/detect-object-injection */
117
120
  Object.defineProperty(this, o, {
118
121
  value: originals[o],
119
122
  enumerable: true,
120
123
  writable: true,
121
124
  });
125
+ /* eslint-enable security/detect-object-injection */
122
126
  });
123
127
  }
124
128
  /**
@@ -193,10 +193,10 @@ exports.validateViews = validateViews;
193
193
  */
194
194
  function validateSessionSecret(secret) {
195
195
  if (typeof secret === 'undefined') {
196
- throw ReferenceError('Session secret is missing (sessions.secret)');
196
+ throw ReferenceError('Session secret is missing (session.secret)');
197
197
  }
198
198
  else if (typeof secret !== 'string') {
199
- throw new TypeError('Session secret must be a string (sessions.secret)');
199
+ throw new TypeError('Session secret must be a string (session.secret)');
200
200
  }
201
201
  return secret;
202
202
  }
@@ -211,10 +211,10 @@ exports.validateSessionSecret = validateSessionSecret;
211
211
  */
212
212
  function validateSessionTtl(ttl) {
213
213
  if (typeof ttl === 'undefined') {
214
- throw ReferenceError('Session ttl is missing (sessions.ttl)');
214
+ throw ReferenceError('Session ttl is missing (session.ttl)');
215
215
  }
216
216
  else if (typeof ttl !== 'number') {
217
- throw new TypeError('Session ttl must be an integer (sessions.ttl)');
217
+ throw new TypeError('Session ttl must be an integer (session.ttl)');
218
218
  }
219
219
  return ttl;
220
220
  }
@@ -229,10 +229,10 @@ exports.validateSessionTtl = validateSessionTtl;
229
229
  */
230
230
  function validateSessionName(name) {
231
231
  if (typeof name === 'undefined') {
232
- throw ReferenceError('Session name is missing (sessions.name)');
232
+ throw ReferenceError('Session name is missing (session.name)');
233
233
  }
234
234
  else if (typeof name !== 'string') {
235
- throw new TypeError('Session name must be a string (sessions.name)');
235
+ throw new TypeError('Session name must be a string (session.name)');
236
236
  }
237
237
  return name;
238
238
  }
@@ -247,10 +247,10 @@ exports.validateSessionName = validateSessionName;
247
247
  */
248
248
  function validateSessionSecure(secure) {
249
249
  if (typeof secure === 'undefined') {
250
- throw ReferenceError('Session secure flag is missing (sessions.secure)');
250
+ throw ReferenceError('Session secure flag is missing (session.secure)');
251
251
  }
252
252
  else if (typeof secure !== 'boolean') {
253
- throw new TypeError('Session secure flag must be boolean (sessions.secure)');
253
+ throw new TypeError('Session secure flag must be boolean (session.secure)');
254
254
  }
255
255
  return secure;
256
256
  }
@@ -302,11 +302,11 @@ function validateSessionCookieSameSite(cookieSameSite, defaultFlag) {
302
302
  throw new TypeError('validateSessionCookieSameSite() requires an explicit default flag');
303
303
  }
304
304
  else if (!validValues.includes(defaultFlag)) {
305
- throw new TypeError('validateSessionCookieSameSite() default flag must be set to one of true, false, Strict, Lax or None (sessions.cookieSameSite)');
305
+ throw new TypeError('validateSessionCookieSameSite() default flag must be set to one of true, false, Strict, Lax or None (session.cookieSameSite)');
306
306
  }
307
307
  const value = cookieSameSite !== undefined ? cookieSameSite : defaultFlag;
308
308
  if (!validValues.includes(value)) {
309
- throw new TypeError('SameSite flag must be set to one of true, false, Strict, Lax or None (sessions.cookieSameSite)');
309
+ throw new TypeError('SameSite flag must be set to one of true, false, Strict, Lax or None (session.cookieSameSite)');
310
310
  }
311
311
  return value;
312
312
  }
@@ -435,7 +435,7 @@ function ingest(config = {}) {
435
435
  // Public URL from which the app will be served
436
436
  mountUrl: validateMountUrl(config.mountUrl),
437
437
  // Session
438
- sessions: validateSessionObject(config.session, (session) => ({
438
+ session: validateSessionObject(config.session, (session) => ({
439
439
  name: validateSessionName(session.name),
440
440
  secret: validateSessionSecret(session.secret),
441
441
  secure: validateSessionSecure(session.secure),
@@ -462,29 +462,3 @@ function ingest(config = {}) {
462
462
  return parsed;
463
463
  }
464
464
  exports.default = ingest;
465
- // module.exports = {
466
- // ingest,
467
- // validateAllowPageEdit,
468
- // validateUseStickyEdit,
469
- // validateContentSecurityPolicies,
470
- // validateHeadersObject,
471
- // validateHeadersDisabled,
472
- // validateI18nObject,
473
- // validateI18nDirs,
474
- // validateI18nLocales,
475
- // validateMountController,
476
- // validateMountUrl,
477
- // validatePhase,
478
- // validateServiceName,
479
- // validateSessionExpiryController,
480
- // validateSessionObject,
481
- // validateSessionCookiePath,
482
- // validateSessionCookieSameSite,
483
- // validateSessionName,
484
- // validateSessionSecret,
485
- // validateSessionSecure,
486
- // validateSessionStore,
487
- // validateSessionTtl,
488
- // validateViewsObject,
489
- // validateViews,
490
- // };
@@ -61,12 +61,11 @@ function configure(config = {}) {
61
61
  plugin.configure(config);
62
62
  });
63
63
  // Extract config
64
- // TODO: Validate/sanitise and deep-freeze object
65
64
  const { mountUrl = '/', views = [], session = {
66
65
  secret: 'secret',
67
66
  name: 'casasession',
68
67
  secure: false,
69
- ttl: 60 * 60,
68
+ ttl: 3600,
70
69
  cookieSameSite: true,
71
70
  cookiePath: '/',
72
71
  store: undefined,
@@ -1 +1 @@
1
- module.exports = __dirname;
1
+ module.exports = __dirname;
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const logger_js_1 = __importDefault(require("./logger.js"));
7
- const log = (0, logger_js_1.default)('function:end-session');
7
+ const log = (0, logger_js_1.default)('lib:end-session');
8
8
  /**
9
9
  * A convenience for ending the current session, but retaining some data in it,
10
10
  * like the current language. It persists an empty session before regenerating
@@ -21,6 +21,9 @@ function endSession(req, next) {
21
21
  const { language } = req.session;
22
22
  Object.entries(req.session).forEach(([k]) => {
23
23
  if (!['cookie'].includes(k)) {
24
+ // ESLint disabled as `Object.entries()` returns "own" properties, and
25
+ // all values are being null'd, so not assigned any user-controlled values
26
+ /* eslint-disable-next-line security/detect-object-injection */
24
27
  req.session[k] = null;
25
28
  }
26
29
  });
@@ -10,7 +10,7 @@ export class PageField {
10
10
  * @throws {Error} When run on a complex field
11
11
  */
12
12
  getValue(obj?: object): any;
13
- putValue(obj: any, value: any): PageField;
13
+ putValue(obj?: any, value?: undefined): PageField;
14
14
  get name(): string;
15
15
  get meta(): object;
16
16
  /**
@@ -46,7 +46,7 @@ export class PageField {
46
46
  * @param {ValidateContext} context Contextual information
47
47
  * @returns {ValidationError[]} Errors, or an empty array if all valid
48
48
  */
49
- runValidators(value: any, context: any): ValidationError[];
49
+ runValidators(value: any, context?: any): ValidationError[];
50
50
  applyProcessors(value: any): any;
51
51
  /**
52
52
  * Apply all conditions to get the resulting boolean
package/dist/lib/field.js CHANGED
@@ -107,7 +107,7 @@ class PageField {
107
107
  }
108
108
  throw new Error('Not yet supporting complex field types');
109
109
  }
110
- putValue(obj = Object.create(null), value) {
110
+ putValue(obj = Object.create(null), value = undefined) {
111
111
  if (!__classPrivateFieldGet(this, _PageField_meta, "f").complex) {
112
112
  /* eslint-disable-next-line no-param-reassign */
113
113
  obj[__classPrivateFieldGet(this, _PageField_name, "f")] = value;
@@ -174,14 +174,24 @@ class PageField {
174
174
  * @param {ValidateContext} context Contextual information
175
175
  * @returns {ValidationError[]} Errors, or an empty array if all valid
176
176
  */
177
- runValidators(value, context) {
177
+ runValidators(value, context = Object.create(null)) {
178
+ var _a;
178
179
  // Skip validation if the field is empty and optional
179
180
  if (__classPrivateFieldGet(this, _PageField_meta, "f").optional && (0, utils_js_1.isEmpty)(value)) {
180
181
  return [];
181
182
  }
183
+ // Skip validation if conditions are not met
184
+ // We duplicate value in context.fieldValue for historical reasons
185
+ context.fieldValue = (_a = context.fieldValue) !== null && _a !== void 0 ? _a : value;
186
+ if (!this.testConditions(context)) {
187
+ return [];
188
+ }
182
189
  let errors = [];
183
190
  for (let i = 0, l = __classPrivateFieldGet(this, _PageField_validators, "f").length; i < l; i++) {
191
+ // ESLint disabled as `i` is an integer
192
+ /* eslint-disable security/detect-object-injection */
184
193
  const fieldErrors = __classPrivateFieldGet(this, _PageField_validators, "f")[i].validate(value, context).map((e) => e.withContext(Object.assign(Object.assign({}, context), { validator: __classPrivateFieldGet(this, _PageField_validators, "f")[i].name })));
194
+ /* eslint-enable security/detect-object-injection */
185
195
  errors = [
186
196
  ...errors,
187
197
  ...(fieldErrors !== null && fieldErrors !== void 0 ? fieldErrors : []),
@@ -199,12 +209,17 @@ class PageField {
199
209
  let processedValue = value;
200
210
  // Some of the validators may have their own "sanitise()" methods. These
201
211
  // should be run before any other processors
212
+ // ESLint disabled as `i` is an integer
213
+ /* eslint-disable security/detect-object-injection */
202
214
  for (let i = 0, l = __classPrivateFieldGet(this, _PageField_validators, "f").length; i < l; i++) {
203
215
  if (isFunction(__classPrivateFieldGet(this, _PageField_validators, "f")[i].sanitise)) {
204
216
  processedValue = __classPrivateFieldGet(this, _PageField_validators, "f")[i].sanitise(processedValue);
205
217
  }
206
218
  }
219
+ /* eslint-enable security/detect-object-injection */
207
220
  for (let i = 0, l = __classPrivateFieldGet(this, _PageField_processors, "f").length; i < l; i++) {
221
+ // ESLint disabled as `i` is an integer
222
+ /* eslint-disable-next-line security/detect-object-injection */
208
223
  processedValue = __classPrivateFieldGet(this, _PageField_processors, "f")[i](processedValue);
209
224
  }
210
225
  return processedValue;
@@ -228,6 +243,8 @@ class PageField {
228
243
  };
229
244
  let result = true;
230
245
  for (let i = 0, l = __classPrivateFieldGet(this, _PageField_conditions, "f").length; i < l; i++) {
246
+ // ESLint disabled as `i` is an integer
247
+ /* eslint-disable-next-line security/detect-object-injection */
231
248
  result = result && __classPrivateFieldGet(this, _PageField_conditions, "f")[i](context);
232
249
  }
233
250
  return result;
@@ -1,4 +1,4 @@
1
- declare function _default(ns: any): {
1
+ declare function _default(namespace: any): {
2
2
  trace: any;
3
3
  debug: any;
4
4
  info: any;
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const debug_1 = __importDefault(require("debug"));
7
7
  const casaDebugger = (0, debug_1.default)('casa');
8
- exports.default = (ns) => {
9
- const logger = casaDebugger.extend(ns);
8
+ exports.default = (namespace) => {
9
+ const logger = casaDebugger.extend(namespace);
10
10
  return {
11
11
  trace: logger.extend('trace'),
12
12
  debug: logger.extend('debug'),
@@ -14,6 +14,8 @@ const { all: deepmergeAll } = deepmerge_1.default;
14
14
  const combineMerge = (target, source, options) => {
15
15
  const destination = target.slice();
16
16
  source.forEach((item, index) => {
17
+ // ESLint disabled as `index` is only an integer
18
+ /* eslint-disable security/detect-object-injection */
17
19
  if (typeof destination[index] === 'undefined') {
18
20
  destination[index] = options.cloneUnlessOtherwiseSpecified(item, options);
19
21
  }
@@ -23,6 +25,7 @@ const combineMerge = (target, source, options) => {
23
25
  else if (target.indexOf(item) === -1) {
24
26
  destination.push(item);
25
27
  }
28
+ /* eslint-enable security/detect-object-injection */
26
29
  });
27
30
  return destination;
28
31
  };
@@ -75,6 +78,10 @@ function renderAsAttributes(attrsObject) {
75
78
  const attrsList = [];
76
79
  if (typeof attrsObject === 'object') {
77
80
  Object.keys(attrsObject).forEach((key) => {
81
+ // ESLint disable as `attrsObject` is dev-controlled, `Object.keys()` has
82
+ // been used (to get "own" properties) and `m` is one of the characters
83
+ // found by the regex.
84
+ /* eslint-disable security/detect-object-injection */
78
85
  const value = String(attrsObject[key]).replace(/[<>"'&]/g, (m) => ({
79
86
  '<': '&lt;',
80
87
  '>': '&gt;',
@@ -82,6 +89,7 @@ function renderAsAttributes(attrsObject) {
82
89
  '\'': '&#039;',
83
90
  '&': '&amp;',
84
91
  }[m]));
92
+ /* eslint-enable security/detect-object-injection */
85
93
  attrsList.push(`${key}="${value}"`);
86
94
  });
87
95
  }
package/dist/lib/utils.js CHANGED
@@ -46,6 +46,8 @@ function isEmpty(val) {
46
46
  return true;
47
47
  }
48
48
  if (Array.isArray(val) || typeof val === 'object') {
49
+ // ESLint disabled as `k` is an "own property" (thanks to `Object.keys()`)
50
+ /* eslint-disable-next-line security/detect-object-injection */
49
51
  return Object.keys(val).filter((k) => !isEmpty(val[k])).length === 0;
50
52
  }
51
53
  return false;
@@ -31,7 +31,7 @@ class InArray extends ValidatorFactory_js_1.default {
31
31
  if (value !== null && typeof value !== 'undefined') {
32
32
  const search = Array.isArray(value) ? value : [value];
33
33
  for (let i = 0, l = search.length; i < l; i += 1) {
34
- if (source.indexOf(search[i]) > -1) {
34
+ if (source.indexOf(search[parseInt(i, 10)]) > -1) {
35
35
  valid = true;
36
36
  }
37
37
  else {
@@ -23,25 +23,3 @@ exports.default = {
23
23
  strlen: strlen_js_1.default,
24
24
  wordCount: wordCount_js_1.default,
25
25
  };
26
- // const dateObject = require('./dateObject.js');
27
- // const email = require('./email.js');
28
- // const inArray = require('./inArray.js');
29
- // const nino = require('./nino.js');
30
- // const optional = require('./optional.js');
31
- // const postalAddressObject = require('./postalAddressObject.js');
32
- // const regex = require('./regex.js');
33
- // const required = require('./required.js');
34
- // const strlen = require('./strlen.js');
35
- // const wordCount = require('./wordCount.js');
36
- // module.exports = {
37
- // dateObject,
38
- // email,
39
- // inArray,
40
- // nino,
41
- // optional,
42
- // postalAddressObject,
43
- // regex,
44
- // required,
45
- // strlen,
46
- // wordCount,
47
- // };
@@ -66,6 +66,8 @@ class PostalAddressObject extends ValidatorFactory_js_1.default {
66
66
  const reqF = Object.create(null);
67
67
  const reqC = cfg.requiredFields;
68
68
  ['address1', 'address2', 'address3', 'address4', 'postcode'].forEach((k) => {
69
+ // ESLint disabled as `k` is a known value from a constant list
70
+ /* eslint-disable-next-line security/detect-object-injection */
69
71
  reqF[k] = reqC.indexOf(k) > -1;
70
72
  });
71
73
  let valid = true;
@@ -75,8 +77,7 @@ class PostalAddressObject extends ValidatorFactory_js_1.default {
75
77
  const reAddrLine1 = /^\d+|[^\s]+[a-z0-9\-,.&#()/\\:;'" ]+$/i;
76
78
  // UK Postcode regex taken from the dwp java pc checker
77
79
  // https://github.com/dwp/postcode-format-validation
78
- const pc = /^(?![QVX])[A-Z]((?![IJZ])[A-Z][0-9](([0-9]?)|([ABEHMNPRVWXY]?))|([0-9]([0-9]?|[ABCDEFGHJKPSTUW]?))) ?[0-9]((?![CIKMOV])[A-Z]){2}$|^(BFPO)[ ]?[0-9]{1,4}$/i;
79
- const rePostcode = new RegExp(pc, 'i');
80
+ const rePostcode = /^(?![QVX])[A-Z]((?![IJZ])[A-Z][0-9](([0-9]?)|([ABEHMNPRVWXY]?))|([0-9]([0-9]?|[ABCDEFGHJKPSTUW]?))) ?[0-9]((?![CIKMOV])[A-Z]){2}$|^(BFPO)[ ]?[0-9]{1,4}$/i;
80
81
  // [required, regex, strlenmax, error message]
81
82
  const attributes = {
82
83
  address1: [reqF.address1, reAddrLine1, cfg.strlenmax, cfg.errorMsgAddress1],
@@ -85,6 +86,8 @@ class PostalAddressObject extends ValidatorFactory_js_1.default {
85
86
  address4: [reqF.address4, reAddr, cfg.strlenmax, cfg.errorMsgAddress4],
86
87
  postcode: [reqF.postcode, rePostcode, null, cfg.errorMsgPostcode],
87
88
  };
89
+ // ESLint disabled as `k` is a known value from the constant list above
90
+ /* eslint-disable security/detect-object-injection */
88
91
  Object.keys(attributes).forEach((k) => {
89
92
  const attr = attributes[k];
90
93
  const hasProperty = Object.prototype.hasOwnProperty.call(value, k);
@@ -100,6 +103,7 @@ class PostalAddressObject extends ValidatorFactory_js_1.default {
100
103
  }));
101
104
  }
102
105
  });
106
+ /* eslint-enable security/detect-object-injection */
103
107
  }
104
108
  else {
105
109
  valid = false;
@@ -1 +1,2 @@
1
+ export function verifyBody(req: any, res: any, buf: any, encoding: any): void;
1
2
  export default function bodyParserMiddleware(): import("connect").NextHandleFunction[];