@ti-engine/web-framework 1.15.0 → 1.16.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/CHANGELOG.md +7 -0
- package/bin/web-server.js +1 -1
- package/components/web-config-env.js +7 -3
- package/components/web-handlers.js +18 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This document will contain the list of changes made to the framework. The format is based on the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
|
|
4
4
|
|
|
5
|
+
## Version 1.16.0
|
|
6
|
+
|
|
7
|
+
Support explicitly trusted request origins so state-changing requests (e.g. login) work behind proxies that do not present the app's external host — most notably GitHub Codespaces port forwarding (CA-90).
|
|
8
|
+
|
|
9
|
+
* feat(web-framework): add `TI_WEB_TRUSTED_ORIGINS` (comma-separated) / `config.trustedOrigins`. The `originRefererValidationHandler` now accepts a non-GET request whose `Origin`/`Referer` matches the server-reconstructed base URL **or** any configured trusted origin. Previously such a request behind a proxy that rewrote/omitted the forwarded host was rejected with `E_WEB_INVALID_REQUEST_PARAMETERS` (HTTP 403). Backward compatible (empty list = prior behavior); the CSRF double-submit token check is unchanged and still enforced
|
|
10
|
+
* build(release): bump package version from `1.15.0` to `1.16.0`
|
|
11
|
+
|
|
5
12
|
## Version 1.15.0
|
|
6
13
|
|
|
7
14
|
A dedicated health endpoint, a `TI_WEB_AUTH_METHODS` env override, and login-page gating for every auth method — completing the container-friendly auth/health story for the competence deployment (CA-90).
|
package/bin/web-server.js
CHANGED
|
@@ -301,7 +301,7 @@ class TiWebServer extends ServiceConsumer {
|
|
|
301
301
|
store: new SessionStore()
|
|
302
302
|
} ) );
|
|
303
303
|
this.#webServer.use( webHandlers.csrfInitHandler( this ) );
|
|
304
|
-
this.#webServer.use( webHandlers.originRefererValidationHandler() );
|
|
304
|
+
this.#webServer.use( webHandlers.originRefererValidationHandler( this ) );
|
|
305
305
|
this.#webServer.use( webHandlers.csrfProtectionHandler() );
|
|
306
306
|
|
|
307
307
|
// Set up the web server routes:
|
|
@@ -14,9 +14,10 @@ const tools = require( "@ti-engine/core/tools" );
|
|
|
14
14
|
* Applies TI_WEB_* environment-variable overrides onto an (already-merged) web server configuration object.
|
|
15
15
|
* Each override is applied ONLY when its environment variable is defined, so an absent variable leaves the
|
|
16
16
|
* configured/default value untouched (fully backward compatible). This gives ti-engine web servers 12-factor,
|
|
17
|
-
* container-friendly control over network binding, TLS, the session cookie secret,
|
|
18
|
-
* methods without editing config files. Note `TI_WEB_AUTH_METHODS`
|
|
19
|
-
*
|
|
17
|
+
* container-friendly control over network binding, TLS, the session cookie secret, the enabled authentication
|
|
18
|
+
* methods, and the trusted request origins without editing config files. Note `TI_WEB_AUTH_METHODS` and
|
|
19
|
+
* `TI_WEB_TRUSTED_ORIGINS` fully REPLACE their config arrays (`auth.enabledMethods` / `trustedOrigins`) rather than
|
|
20
|
+
* merging — the config-file merge is by-index and cannot cleanly override an array.
|
|
20
21
|
*
|
|
21
22
|
* @method
|
|
22
23
|
* @param {Object} config The web server configuration to augment (mutated in place and returned).
|
|
@@ -54,6 +55,9 @@ function applyWebConfigEnvOverrides( config, env = process.env ) {
|
|
|
54
55
|
config.auth = config.auth || {};
|
|
55
56
|
config.auth.enabledMethods = env.TI_WEB_AUTH_METHODS.split( "," ).map( ( method ) => method.trim() ).filter( ( method ) => method.length > 0 );
|
|
56
57
|
}
|
|
58
|
+
if ( env.TI_WEB_TRUSTED_ORIGINS !== undefined ) {
|
|
59
|
+
config.trustedOrigins = env.TI_WEB_TRUSTED_ORIGINS.split( "," ).map( ( origin ) => origin.trim() ).filter( ( origin ) => origin.length > 0 );
|
|
60
|
+
}
|
|
57
61
|
return config;
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -690,19 +690,30 @@ module.exports.webAppHandler = ( instance ) => {
|
|
|
690
690
|
* @returns {ExpressHandler}
|
|
691
691
|
* @public
|
|
692
692
|
*/
|
|
693
|
-
module.exports.originRefererValidationHandler = () => {
|
|
693
|
+
module.exports.originRefererValidationHandler = ( instance ) => {
|
|
694
694
|
return ( request, response, next ) => {
|
|
695
695
|
if ( request.method === "GET" || request.method === "HEAD" || request.method === "OPTIONS" ) {
|
|
696
696
|
next();
|
|
697
697
|
} else {
|
|
698
|
-
const expectedOrigin = getBaseUrl( request );
|
|
699
698
|
const providedOrigin = getRequestOrigin( request );
|
|
700
|
-
// If the browser didn
|
|
701
|
-
if ( providedOrigin
|
|
702
|
-
logger.log( `Issue identified with origin/referer mismatch. Expected '${ expectedOrigin }', received '${ providedOrigin }'.`, logger.logSeverity.WARNING );
|
|
703
|
-
next( exceptions.raise( exceptions.exceptionCode.E_WEB_INVALID_REQUEST_PARAMETERS, null, exceptions.httpCode.C_403 ) );
|
|
704
|
-
} else {
|
|
699
|
+
// If the browser didn't send Origin/Referer (normal for same-origin form POSTs), let CSRF middleware handle protection instead of blocking here:
|
|
700
|
+
if ( !providedOrigin ) {
|
|
705
701
|
next();
|
|
702
|
+
} else {
|
|
703
|
+
// Accept the origin the server reconstructs from the request, plus any explicitly trusted origins
|
|
704
|
+
// (TI_WEB_TRUSTED_ORIGINS / config.trustedOrigins). The trusted list is needed behind proxies that do
|
|
705
|
+
// not present the external host to the app (e.g. GitHub Codespaces port forwarding), where the browser
|
|
706
|
+
// Origin cannot be reconstructed from the forwarded headers.
|
|
707
|
+
const configured = ( instance && instance.serviceConfig && Array.isArray( instance.serviceConfig.trustedOrigins ) ) ? instance.serviceConfig.trustedOrigins : [];
|
|
708
|
+
const allowedOrigins = [ getBaseUrl( request ) ].concat( configured );
|
|
709
|
+
const normalizedProvided = String( providedOrigin ).trim().toLowerCase();
|
|
710
|
+
const isAllowed = allowedOrigins.some( ( origin ) => String( origin ).trim().toLowerCase() === normalizedProvided );
|
|
711
|
+
if ( isAllowed ) {
|
|
712
|
+
next();
|
|
713
|
+
} else {
|
|
714
|
+
logger.log( `Issue identified with origin/referer mismatch. Received '${ providedOrigin }'; expected one of [ ${ allowedOrigins.join( ", " ) } ].`, logger.logSeverity.WARNING );
|
|
715
|
+
next( exceptions.raise( exceptions.exceptionCode.E_WEB_INVALID_REQUEST_PARAMETERS, null, exceptions.httpCode.C_403 ) );
|
|
716
|
+
}
|
|
706
717
|
}
|
|
707
718
|
}
|
|
708
719
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ti-engine/web-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "A web-framework based on the ti-engine. It provides a customizable ready-to-use web-server microservice and a set of tools for creating web applications. NOTICE: This is still a work in progress and the full architecture, design, and functionality are not available!",
|
|
5
5
|
"author": "Boris Kostadinov <kostadinov.boris@gmail.com>",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|