@dwp/govuk-casa 8.2.1 → 8.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [8.2.2](https://github.com/dwp/govuk-casa/compare/8.2.1...8.2.2) (2022-05-23)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * escape from sticky edit on return to edit origin in a proxied app ([9303af1](https://github.com/dwp/govuk-casa/commit/9303af140ec383801741d50f3404fd7cfe930d90))
11
+
5
12
  ### [8.2.1](https://github.com/dwp/govuk-casa/compare/8.2.0...8.2.1) (2022-05-20)
6
13
 
7
14
 
package/dist/casa.d.ts CHANGED
@@ -122,6 +122,10 @@ export type MutableRouter = import('./lib/index').MutableRouter;
122
122
  * Configuration options
123
123
  */
124
124
  export type ConfigurationOptions = {
125
+ /**
126
+ * Prefix for all URLS in browser address bar
127
+ */
128
+ mountUrl?: string | undefined;
125
129
  /**
126
130
  * Template directories
127
131
  */
package/dist/casa.js CHANGED
@@ -126,6 +126,7 @@ exports.nunjucksFilters = nunjucksFilters;
126
126
  * Configure some middleware for use in creating a new CASA app.
127
127
  *
128
128
  * @typedef {object} ConfigurationOptions Configuration options
129
+ * @property {string} [mountUrl] Prefix for all URLS in browser address bar
129
130
  * @property {string[]} [views=[]] Template directories
130
131
  * @property {SessionOptions} [session] Session configuration
131
132
  * @property {Page[]} [pages=[]] Pages the represent waypoints
@@ -28,12 +28,11 @@ export function validateI18nLocales(locales?: any[]): any[];
28
28
  /**
29
29
  * Validates and sanitises mount url.
30
30
  *
31
- * @param {string} mountUrl URL from which Express app will be served.
32
- * @param {string} name Name of the URL type (Mount URL, or Proxy Mount URL).
31
+ * @param {string} mountUrl Prefix for all URLs in the browser address bar
33
32
  * @throws {SyntaxError} For invalid URL.
34
- * @returns {string} Sanitised URL.
33
+ * @returns {string|undefined} Sanitised URL.
35
34
  */
36
- export function validateMountUrl(mountUrl: string, name?: string): string;
35
+ export function validateMountUrl(mountUrl: string): string | undefined;
37
36
  /**
38
37
  * Validates and sanitises sessions object.
39
38
  *
@@ -75,17 +75,16 @@ exports.validateI18nLocales = validateI18nLocales;
75
75
  /**
76
76
  * Validates and sanitises mount url.
77
77
  *
78
- * @param {string} mountUrl URL from which Express app will be served.
79
- * @param {string} name Name of the URL type (Mount URL, or Proxy Mount URL).
78
+ * @param {string} mountUrl Prefix for all URLs in the browser address bar
80
79
  * @throws {SyntaxError} For invalid URL.
81
- * @returns {string} Sanitised URL.
80
+ * @returns {string|undefined} Sanitised URL.
82
81
  */
83
- function validateMountUrl(mountUrl, name = 'Mount URL') {
82
+ function validateMountUrl(mountUrl) {
84
83
  if (typeof mountUrl === 'undefined') {
85
- return '/';
84
+ return undefined;
86
85
  }
87
86
  if (!mountUrl.match(/\/$/)) {
88
- throw new SyntaxError(`${name} must include a trailing slash (/)`);
87
+ throw new SyntaxError('mountUrl must include a trailing slash (/)');
89
88
  }
90
89
  return mountUrl;
91
90
  }
@@ -382,10 +381,7 @@ function ingest(config = {}) {
382
381
  dirs: validateI18nDirs(i18n.dirs),
383
382
  locales: validateI18nLocales(i18n.locales),
384
383
  })),
385
- // !!! DEPRECATION NOTICE !!!
386
- // This will be removed in next major version
387
- //
388
- // Public URL from which the app will be served
384
+ // URL that will prefix all URLs in the browser address bar
389
385
  mountUrl: validateMountUrl(config.mountUrl),
390
386
  // Session
391
387
  session: validateSessionObject(config.session, (session) => ({
@@ -16,6 +16,7 @@ const nunjucks_js_1 = __importDefault(require("./nunjucks.js"));
16
16
  const static_js_1 = __importDefault(require("../routes/static.js"));
17
17
  const ancillary_js_1 = __importDefault(require("../routes/ancillary.js"));
18
18
  const journey_js_1 = __importDefault(require("../routes/journey.js"));
19
+ const strip_proxy_path_js_1 = __importDefault(require("../middleware/strip-proxy-path.js"));
19
20
  const pre_js_1 = __importDefault(require("../middleware/pre.js"));
20
21
  const post_js_1 = __importDefault(require("../middleware/post.js"));
21
22
  const session_js_1 = __importDefault(require("../middleware/session.js"));
@@ -23,8 +24,6 @@ const i18n_js_1 = __importDefault(require("../middleware/i18n.js"));
23
24
  const data_js_1 = __importDefault(require("../middleware/data.js"));
24
25
  const body_parser_js_1 = __importDefault(require("../middleware/body-parser.js"));
25
26
  const csrf_js_1 = __importDefault(require("../middleware/csrf.js"));
26
- const logger_js_1 = __importDefault(require("./logger.js"));
27
- const log = (0, logger_js_1.default)('lib:configure');
28
27
  /**
29
28
  * @typedef {import('../casa').ConfigurationOptions} ConfigurationOptions
30
29
  */
@@ -48,7 +47,7 @@ function configure(config = {}) {
48
47
  plugin.configure(config);
49
48
  });
50
49
  // Extract config
51
- const { mountUrl = '/', views = [], session = {
50
+ const { mountUrl, views = [], session = {
52
51
  secret: 'secret',
53
52
  name: 'casasession',
54
53
  secure: false,
@@ -134,54 +133,10 @@ function configure(config = {}) {
134
133
  const mount = (app, { route = '/' } = {}) => {
135
134
  nunjucksEnv.express(app);
136
135
  app.set('view engine', 'njk');
137
- // !!! DEPRECATION NOTICE !!!
138
- // This provides a non-breaking pathway to replacing `mountUrl` with
139
- // `req.baseUrl` in all internal route handlers/middleware for services
140
- // that use a proxy path in their mount point.
141
- //
142
- // In some cases, the URL on which `app` instance is mounted might include a
143
- // proxy path so that it can handle incoming requests that have had a path
144
- // prepended to it by an intermediary, such as nginx. This would be common
145
- // in a hosting environment that serves several separate applications.
146
- //
147
- // This bit of middleware removes that proxy path segment from the request
148
- // so that all subsequent middleware behave as if it was never present.
149
- //
150
- // e.g. Where the proxy path is `my-proxy`, then a request to
151
- // `/my-proxy/app` will be seen as `/app` in all subsequent middleware, and
152
- // all URLs generated for the browser will use `/app`.
153
- //
154
- // Using `config.mountUrl` rather than `mountUrl` here to test whether the
155
- // consumer explicitly set a `mountUrl`, in which case we're dealing with
156
- // backwards-compatibility mode.
157
- //
158
- // This intervention would not be needed for apps that omit `mountUrl` as if
159
- // so, it's assumed they're following the guidance for setting up a proxy
160
- // as described in `docs/guides/setup-behind-a-proxy.md`.
161
- if (config.mountUrl) {
162
- log.warn('[DEPRECATION WARNING] Using configuration attribute, mountUrl. This will be removed in an upcoming major version');
163
- app.use((req, res, next) => {
164
- // Mimic what the `docs/guides/setup-behind-a-proxy.md` guidance
165
- // recommends for stripping off any proxy prefixes to leave just the
166
- // "mountUrl" remaining.
167
- const originalBaseUrl = req.baseUrl;
168
- req.baseUrl = mountUrl.replace(/\/$/, '');
169
- // If the app has been mounted directly on the specific `mountUrl`, then
170
- // there's nothing we need to do and can let this request pass-through.
171
- if (req.baseUrl === originalBaseUrl) {
172
- next();
173
- }
174
- else if (req.__CASA_BASE_URL_REWRITTEN__) {
175
- delete req.__CASA_BASE_URL_REWRITTEN__;
176
- next();
177
- }
178
- else {
179
- // Issuing this call will re-run this same middleware, so we use this
180
- // `__CASA_BASE_URL_REWRITTEN__` flag to prevent recursion.
181
- req.__CASA_BASE_URL_REWRITTEN__ = true;
182
- req.app.handle(req, res, next);
183
- }
184
- });
136
+ // If a `mountUrl` has been defined, then we're potentially in "proxy mode",
137
+ // in which we strip the proxy path prefix from the incoming request URLs.
138
+ if (mountUrl) {
139
+ app.use((0, strip_proxy_path_js_1.default)({ mountUrl }));
185
140
  }
186
141
  // Attach a handler to redirect requests for `/` to the first waypoint in
187
142
  // the plan
@@ -0,0 +1,4 @@
1
+ declare function _default({ mountUrl, }: {
2
+ mountUrl?: string | undefined;
3
+ }): ((req: any, res: any, next: any) => void)[];
4
+ export default _default;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ // Strip any "proxy path" prefix present on the request URL
3
+ //
4
+ // The default "mountUrl" will be match whatever path that the CASA app
5
+ // instance will be mounted onto. So if you mount on `/a/b/c` then all
6
+ // URLs generated for the browser will be prefixed with `/a/b/c`.
7
+ //
8
+ // Defining a `mountUrl` will change that behaviour into a "proxy mode".
9
+ // This mode assumes you have a forwarding proxy that will alter
10
+ // the incoming request paths from `mountUrl` to the original path you
11
+ // have mounted this CASA app instance onto.
12
+ //
13
+ // For example, if you mount the app on `/a/b/c/x`, but want the browser
14
+ // URLs to just use the `/x` prefix, then pass a `mountUrl` of `/x`.
15
+ //
16
+ // See docs in `docs/guides/setup-behind-a-proxy.md`
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ const logger_js_1 = __importDefault(require("../lib/logger.js"));
22
+ const log = (0, logger_js_1.default)('casa:middleware:strip-proxy-path');
23
+ exports.default = ({ mountUrl = '/', }) => [
24
+ (req, res, next) => {
25
+ // Assume everything before `mountUrl` is the proxy path prefix and remove it
26
+ const originalBaseUrl = req.baseUrl;
27
+ req.baseUrl = mountUrl.replace(/\/$/, '');
28
+ // If the app has been mounted directly on the specific `mountUrl`, then
29
+ // there's nothing we need to do and can let this request pass-through.
30
+ if (req.baseUrl === originalBaseUrl) {
31
+ next();
32
+ }
33
+ else if (req.__CASA_BASE_URL_REWRITTEN__) {
34
+ delete req.__CASA_BASE_URL_REWRITTEN__;
35
+ next();
36
+ }
37
+ else {
38
+ // Strip the proxy path prefix from the original URL so that
39
+ // subsequnt middleware sees the URL path as though proxy wasn't there.
40
+ // req.url will already have the proxy prefix and mountUrl removed.
41
+ /* eslint-disable security/detect-non-literal-regexp */
42
+ log.trace(`req.originalUrl before proxy stripping: ${req.originalUrl}`);
43
+ req.originalUrl = req.originalUrl.replace(new RegExp(`^/.+?${mountUrl}`), mountUrl);
44
+ log.trace(`req.originalUrl after proxy stripping: ${req.originalUrl}`);
45
+ /* eslint-enable security/detect-non-literal-regexp */
46
+ // Issuing this call will re-run this same middleware, so we use this
47
+ // `__CASA_BASE_URL_REWRITTEN__` flag to prevent recursion.
48
+ req.__CASA_BASE_URL_REWRITTEN__ = true;
49
+ req.app.handle(req, res, next);
50
+ }
51
+ },
52
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwp/govuk-casa",
3
- "version": "8.2.1",
3
+ "version": "8.2.2",
4
4
  "description": "A framework for building GOVUK Collect-And-Submit-Applications",
5
5
  "repository": {
6
6
  "type": "git",