@ti-engine/web-framework 1.19.0 → 1.20.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/.env +4 -4
- package/CHANGELOG.md +384 -353
- package/README.md +73 -73
- package/bin/build/post-install.js +18 -18
- package/bin/localization/web-server-labels.json +27 -27
- package/bin/static/.well-known/appspecific/com.chrome.devtools.json +5 -5
- package/bin/static/fragments/components/component-notification-bar.html +21 -21
- package/bin/static/fragments/components/component-sidebar.html +33 -33
- package/bin/static/fragments/components/component-tooltip.html +10 -10
- package/bin/static/fragments/components/component-topbar.html +5 -5
- package/bin/static/fragments/frame-administration.html +2 -2
- package/bin/static/fragments/frame-application.html +18 -18
- package/bin/static/fragments/frame-dashboard.html +2 -2
- package/bin/static/fragments/frame-login.html +119 -119
- package/bin/static/fragments/frame-not-found.html +2 -2
- package/bin/static/fragments/frame-profile.html +2 -2
- package/bin/static/index.html +22 -22
- package/bin/static/scripts/ti-charts.js +1591 -1591
- package/bin/static/scripts/ti-framework.css +3194 -3194
- package/bin/static/scripts/ti-framework.js +1427 -1427
- package/bin/static/scripts/ti-theme-black-glass.css +216 -216
- package/bin/static/scripts/ti-theme-daylight.css +87 -87
- package/bin/web-app-manager.js +660 -663
- package/bin/web-server.js +936 -937
- package/bin/web-server.json +48 -48
- package/components/admin-config-handlers.js +95 -92
- package/components/auth-manager.js +438 -442
- package/components/authorization.js +135 -135
- package/components/config-change-notifier.js +98 -98
- package/components/config-registry.js +257 -260
- package/components/config-service.js +363 -360
- package/components/config-store.js +244 -246
- package/components/definitions.types.js +28 -26
- package/components/session-store.js +113 -110
- package/components/user.js +134 -132
- package/components/web-config-env.js +85 -85
- package/components/web-handlers.js +803 -800
- package/package.json +139 -67
- package/types/bin/web-app-manager.d.ts +194 -0
- package/types/bin/web-server.d.ts +373 -0
- package/types/components/admin-config-handlers.d.ts +11 -0
- package/types/components/auth-manager.d.ts +125 -0
- package/types/components/authorization.d.ts +54 -0
- package/types/components/config-change-notifier.d.ts +73 -0
- package/types/components/config-registry.d.ts +149 -0
- package/types/components/config-service.d.ts +218 -0
- package/types/components/config-store.d.ts +128 -0
- package/types/components/definitions.types.d.ts +31 -0
- package/types/components/session-store.d.ts +56 -0
- package/types/components/user.d.ts +83 -0
- package/types/components/web-config-env.d.ts +17 -0
- package/types/components/web-handlers.d.ts +23 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
export = TiWebServer;
|
|
2
|
+
import ServiceConsumer = require("@ti-engine/core/service-consumer");
|
|
3
|
+
export type NodeServer = import("node:http").Server;
|
|
4
|
+
export type TiWebServiceConfiguration = ServiceConfiguration;
|
|
5
|
+
export type TiWebApplicationConfig = {
|
|
6
|
+
classPath: string;
|
|
7
|
+
};
|
|
8
|
+
export type ApiConfig = {
|
|
9
|
+
endpointEnabled: boolean;
|
|
10
|
+
inventory: ApiInventory;
|
|
11
|
+
requestTimeout: number;
|
|
12
|
+
};
|
|
13
|
+
export type SettingsAuth = {
|
|
14
|
+
enabledMethods: string[];
|
|
15
|
+
local: Object;
|
|
16
|
+
oauth2: {
|
|
17
|
+
azure?: SettingsOAuth2Client;
|
|
18
|
+
google?: SettingsOAuth2Client;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type SettingsOAuth2Client = {
|
|
22
|
+
clientID?: string;
|
|
23
|
+
clientSecret?: string;
|
|
24
|
+
callbackUrl?: string;
|
|
25
|
+
discoveryUrl?: string;
|
|
26
|
+
isPublic?: boolean;
|
|
27
|
+
tokenEndpointAuthMethod?: TiTokenEndpointAuthMethod;
|
|
28
|
+
};
|
|
29
|
+
export type SettingsStaticCache = {
|
|
30
|
+
/**
|
|
31
|
+
* The `max-age` for `/static` responses, in SECONDS (not a duration string). `0` means every use is revalidated.
|
|
32
|
+
*/
|
|
33
|
+
maxAge: number;
|
|
34
|
+
/**
|
|
35
|
+
* Whether to add `immutable`. Only correct when the `/static` filenames are content-addressed.
|
|
36
|
+
*/
|
|
37
|
+
immutable: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Path prefixes under `/static` that are served long-lived and `immutable` regardless of the two settings above.
|
|
40
|
+
*/
|
|
41
|
+
immutablePaths: string[];
|
|
42
|
+
};
|
|
43
|
+
export type SettingsCookies = {
|
|
44
|
+
secret: string;
|
|
45
|
+
path: string;
|
|
46
|
+
httpOnly: boolean;
|
|
47
|
+
sameSite: "lax" | "strict" | "none";
|
|
48
|
+
maxAge: number;
|
|
49
|
+
};
|
|
50
|
+
export type ApiInventory = Record<string, Record<string, ServiceAddress>>;
|
|
51
|
+
import type { TiAuthMethod, TiTokenEndpointAuthMethod } from "#auth-manager";
|
|
52
|
+
import type { TiSession } from "#definitions";
|
|
53
|
+
import type User from "#user";
|
|
54
|
+
import type TiWebAppManager from "#web-app-manager";
|
|
55
|
+
import type { ServiceAddress, ServiceConfiguration } from "@ti-engine/core/definitions";
|
|
56
|
+
/** @import { TiAuthMethod, TiTokenEndpointAuthMethod } from "#auth-manager" */
|
|
57
|
+
/** @import { TiSession } from "#definitions" */
|
|
58
|
+
/** @import User from "#user" */
|
|
59
|
+
/** @import TiWebAppManager from "#web-app-manager" */
|
|
60
|
+
/** @import { ServiceAddress, ServiceConfiguration } from "@ti-engine/core/definitions" */
|
|
61
|
+
/**
|
|
62
|
+
* Default unprotected static-asset route matchers. The path segments are matched with `(?:[^/]+\/)*` rather than
|
|
63
|
+
* `(?:.+\/)*`: the inner `[^/]+` cannot also consume the "/" delimiter, so the pattern is unambiguous and matches
|
|
64
|
+
* in linear time. The previous `.+` form was ambiguous and backtracked exponentially on hostile request paths such
|
|
65
|
+
* as `/static/a/a/…/a/x` (no trailing extension) — and these matchers run against the raw request path in
|
|
66
|
+
* {@link TiWebServer#isUnprotectedRoute} BEFORE authentication, so that was a pre-auth denial-of-service vector
|
|
67
|
+
* (CodeQL js/redos). The matched language for realistic asset paths is unchanged.
|
|
68
|
+
*
|
|
69
|
+
* @type {RegExp}
|
|
70
|
+
*/
|
|
71
|
+
declare const RE_STATIC_UNPROTECTED: RegExp;
|
|
72
|
+
/**
|
|
73
|
+
* Default unprotected `/.well-known/` route matcher. See {@link RE_STATIC_UNPROTECTED} for the ReDoS rationale.
|
|
74
|
+
*
|
|
75
|
+
* @type {RegExp}
|
|
76
|
+
*/
|
|
77
|
+
declare const RE_WELL_KNOWN_UNPROTECTED: RegExp;
|
|
78
|
+
/**
|
|
79
|
+
* A web server microservice based on the ti-engine.
|
|
80
|
+
* <br/>
|
|
81
|
+
* Note: The web server is fully functional and already comes with all the necessary fundamentals and security features. However, it is designed to be extended
|
|
82
|
+
* with custom logic and functionality to fit your specific needs. Here is a list of methods that you can override to customize the web server behavior:
|
|
83
|
+
* - {@link TiWebServer#defineWebApplicationRoutes} Override this to define custom web application routes. Remember to call the base method if you want to preserve the default behavior as well (recommended).
|
|
84
|
+
* - {@link TiWebServer#defineUnprotectedRoutes} Override this to define unprotected routes. Remember to call the base method if you want to preserve the default behavior as well (recommended).
|
|
85
|
+
* - {@link TiWebServer#verifySession} Override this to implement custom session verification logic.
|
|
86
|
+
*
|
|
87
|
+
* @class TiWebServer
|
|
88
|
+
* @extends ServiceConsumer
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
declare class TiWebServer extends ServiceConsumer {
|
|
92
|
+
#private;
|
|
93
|
+
/**
|
|
94
|
+
* @constructor
|
|
95
|
+
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
96
|
+
* @param {TiWebServiceConfiguration} serviceConfig The JSON configuration for this service. Note that the configuration provided will be merged with the default web server configuration, and it will override any conflicting properties.
|
|
97
|
+
* @throws {TiException.E_GEN_JS_INTERNAL_ERROR} If the web application manager cannot be loaded.
|
|
98
|
+
*/
|
|
99
|
+
constructor(serviceDomainName: string, serviceConfig: TiWebServiceConfiguration);
|
|
100
|
+
/**
|
|
101
|
+
* Property returning the service configuration JSON.
|
|
102
|
+
*
|
|
103
|
+
* @property
|
|
104
|
+
* @returns {TiWebServiceConfiguration}
|
|
105
|
+
* @override
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
get serviceConfig(): TiWebServiceConfiguration;
|
|
109
|
+
/**
|
|
110
|
+
* Property returning if the web server is currently shutting down.
|
|
111
|
+
*
|
|
112
|
+
* @property
|
|
113
|
+
* @returns {boolean}
|
|
114
|
+
* @public
|
|
115
|
+
*/
|
|
116
|
+
get isShuttingDown(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Property returning the list of static content directories.
|
|
119
|
+
*
|
|
120
|
+
* @property
|
|
121
|
+
* @returns {string[]}
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
get staticContentPaths(): string[];
|
|
125
|
+
/**
|
|
126
|
+
* Property returning the server URL.
|
|
127
|
+
*
|
|
128
|
+
* @property
|
|
129
|
+
* @returns {string}
|
|
130
|
+
* @public
|
|
131
|
+
*/
|
|
132
|
+
get serverUrl(): string;
|
|
133
|
+
/**
|
|
134
|
+
* Property returning the {@link TiWebAppManager} instance.
|
|
135
|
+
*
|
|
136
|
+
* @property
|
|
137
|
+
* @returns {TiWebAppManager}
|
|
138
|
+
* @public
|
|
139
|
+
*/
|
|
140
|
+
get webAppManager(): TiWebAppManager;
|
|
141
|
+
/**
|
|
142
|
+
* Starts the web server.
|
|
143
|
+
*
|
|
144
|
+
* @method
|
|
145
|
+
* @returns {Promise}
|
|
146
|
+
* @override
|
|
147
|
+
* @public
|
|
148
|
+
*/
|
|
149
|
+
onStart(): Promise<any>;
|
|
150
|
+
/**
|
|
151
|
+
* Shuts down the web server.
|
|
152
|
+
*
|
|
153
|
+
* @method
|
|
154
|
+
* @returns {Promise}
|
|
155
|
+
* @override
|
|
156
|
+
* @public
|
|
157
|
+
*/
|
|
158
|
+
onStop(): Promise<any>;
|
|
159
|
+
/**
|
|
160
|
+
* Used to report health status of the service instance for external monitoring.
|
|
161
|
+
* This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
|
|
162
|
+
*
|
|
163
|
+
* @method
|
|
164
|
+
* @override
|
|
165
|
+
* @public
|
|
166
|
+
*/
|
|
167
|
+
reportHealthy(): void;
|
|
168
|
+
/**
|
|
169
|
+
* Used to verify the session of a request.
|
|
170
|
+
*
|
|
171
|
+
* @method
|
|
172
|
+
* @param {TiSession} session
|
|
173
|
+
* @returns {boolean}
|
|
174
|
+
* @public
|
|
175
|
+
*/
|
|
176
|
+
verifySession(session: TiSession): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Hook for the application to augment the freshly-authenticated session (e.g. derive domain roles from an
|
|
179
|
+
* identity store or the org chart). Runs synchronously, once per login, before the framework's additive `admin`
|
|
180
|
+
* role is applied. The default is a no-op. Any test-user role injection is an override of whatever the app derives.
|
|
181
|
+
*
|
|
182
|
+
* @method
|
|
183
|
+
* @virtual
|
|
184
|
+
* @param {TiSession} session
|
|
185
|
+
* @param {Object} [request] Optional Express request object that can be used to read body/cookies/query data.
|
|
186
|
+
* @returns {TiSession}
|
|
187
|
+
* @public
|
|
188
|
+
*/
|
|
189
|
+
augmentSession(session: TiSession, request?: Object): TiSession;
|
|
190
|
+
/**
|
|
191
|
+
* Used to authenticate a user via the specified auth method.
|
|
192
|
+
*
|
|
193
|
+
* @method
|
|
194
|
+
* @param {TiAuthMethod} authMethod
|
|
195
|
+
* @param {Object} [authDetails={}]
|
|
196
|
+
* @returns {Promise}
|
|
197
|
+
* @public
|
|
198
|
+
*/
|
|
199
|
+
authenticate(authMethod: TiAuthMethod, authDetails?: Object): Promise<any>;
|
|
200
|
+
/**
|
|
201
|
+
* Used to set up user authorization according to the specified auth method.
|
|
202
|
+
*
|
|
203
|
+
* @method
|
|
204
|
+
* @param {TiAuthMethod} authMethod
|
|
205
|
+
* @param {URL} currentUrl
|
|
206
|
+
* @param {Object} oidc
|
|
207
|
+
* @returns {Promise<User>}
|
|
208
|
+
* @public
|
|
209
|
+
*/
|
|
210
|
+
authorize(authMethod: TiAuthMethod, currentUrl: URL, oidc: Object): Promise<User>;
|
|
211
|
+
/**
|
|
212
|
+
* Used to get a service mapping if such exists.
|
|
213
|
+
*
|
|
214
|
+
* @method
|
|
215
|
+
* @param {string} serviceVersion
|
|
216
|
+
* @param {string} serviceName
|
|
217
|
+
* @returns {ServiceAddress}
|
|
218
|
+
* @public
|
|
219
|
+
*/
|
|
220
|
+
getServiceAddress(serviceVersion: string, serviceName: string): ServiceAddress;
|
|
221
|
+
/**
|
|
222
|
+
* Used to check if the specified hostname is allowed to access the web server.
|
|
223
|
+
*
|
|
224
|
+
* @method
|
|
225
|
+
* @param {string} hostname
|
|
226
|
+
* @returns {boolean}
|
|
227
|
+
* @public
|
|
228
|
+
*/
|
|
229
|
+
isAllowedHost(hostname: string): boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Used to check if the specified route is unprotected (i.e., does not require authentication). The default unprotected routes are:
|
|
232
|
+
* - /
|
|
233
|
+
* - /static/...
|
|
234
|
+
* - /.well-known/...
|
|
235
|
+
* - /not-found
|
|
236
|
+
* - /app
|
|
237
|
+
* - /app/enter
|
|
238
|
+
* - /app/config
|
|
239
|
+
* - /logout
|
|
240
|
+
* - /login/:method
|
|
241
|
+
* <br/>
|
|
242
|
+
* NOTE: You can define custom unprotected routes by overriding the {@link TiWebServer#defineUnprotectedRoutes} method.
|
|
243
|
+
*
|
|
244
|
+
* @method
|
|
245
|
+
* @param {string} route
|
|
246
|
+
* @returns {boolean}
|
|
247
|
+
* @public
|
|
248
|
+
*/
|
|
249
|
+
isUnprotectedRoute(route: string): boolean;
|
|
250
|
+
/**
|
|
251
|
+
* Used to define the web application routes.
|
|
252
|
+
* <br/>
|
|
253
|
+
* NOTE: Override this to define custom web application routes. Remember to call the base method if you want to preserve the default behavior as well.
|
|
254
|
+
*
|
|
255
|
+
* @method
|
|
256
|
+
* @virtual
|
|
257
|
+
* @public
|
|
258
|
+
*/
|
|
259
|
+
defineWebApplicationRoutes(): void;
|
|
260
|
+
/**
|
|
261
|
+
* Used to define the unprotected routes (i.e., routes that do not require authentication).
|
|
262
|
+
* <br/>
|
|
263
|
+
* NOTE: Override this to define custom unprotected routes. Remember to call the base method if you want to preserve the default behavior as well.
|
|
264
|
+
*
|
|
265
|
+
* @method
|
|
266
|
+
* @virtual
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
269
|
+
defineUnprotectedRoutes(): void;
|
|
270
|
+
/**
|
|
271
|
+
* Registers a custom application route on the underlying Express app.
|
|
272
|
+
* <br/>
|
|
273
|
+
* NOTE: Call this from a {@link TiWebServer#defineWebApplicationRoutes} override AFTER invoking the base method,
|
|
274
|
+
* so the framework's own routes keep priority and any catch-all route you add resolves last (it will still be
|
|
275
|
+
* registered before the framework's own `*splat` 404 handler). It is only valid once the Express app exists —
|
|
276
|
+
* i.e., from within {@link TiWebServer#defineWebApplicationRoutes}, which {@link TiWebServer#onStart} invokes.
|
|
277
|
+
*
|
|
278
|
+
* @method
|
|
279
|
+
* @param {string} method One of the supported routing verbs: get, post, put, patch, delete, options, head, all.
|
|
280
|
+
* @param {string|RegExp} path The route path or pattern.
|
|
281
|
+
* @param {...Function} handlers One or more Express route handlers/middleware.
|
|
282
|
+
* @returns {TiWebServer} This instance, to allow chaining.
|
|
283
|
+
* @public
|
|
284
|
+
*/
|
|
285
|
+
registerRoute(method: string, path: string | RegExp, ...handlers: Function[]): TiWebServer;
|
|
286
|
+
/**
|
|
287
|
+
* Adds a pattern to the unprotected-routes list — routes that bypass the authentication gate. A string is
|
|
288
|
+
* matched exactly against the request path; a RegExp is tested against it. Consulted at request time by
|
|
289
|
+
* {@link TiWebServer#isUnprotectedRoute}.
|
|
290
|
+
* <br/>
|
|
291
|
+
* NOTE: Call this from a {@link TiWebServer#defineUnprotectedRoutes} override AFTER invoking the base method, to
|
|
292
|
+
* extend (rather than replace) the defaults.
|
|
293
|
+
*
|
|
294
|
+
* @method
|
|
295
|
+
* @param {string|RegExp} pattern The exact path (string) or path matcher (RegExp) to treat as unprotected.
|
|
296
|
+
* @returns {TiWebServer} This instance, to allow chaining.
|
|
297
|
+
* @public
|
|
298
|
+
*/
|
|
299
|
+
addUnprotectedRoute(pattern: string | RegExp): TiWebServer;
|
|
300
|
+
/**
|
|
301
|
+
* Resolves a `staticCache` configuration block into the policy the `/static` mounts apply, filling in
|
|
302
|
+
* {@link TiWebServer.#STATIC_CACHE_DEFAULTS} per key and rejecting values that cannot be honored. Pure: problems
|
|
303
|
+
* are returned as `warnings` rather than logged, so the caller decides how to surface them and a test can assert
|
|
304
|
+
* on them. Static and exposed for unit testing — not part of the customization surface.
|
|
305
|
+
* <br/>
|
|
306
|
+
* `maxAge` is a whole number of SECONDS, mapping 1:1 onto the `Cache-Control` directive — express's `"1y"`-style
|
|
307
|
+
* duration strings are NOT accepted, and are reported rather than silently reinterpreted as milliseconds.
|
|
308
|
+
* <br/>
|
|
309
|
+
* `immutable` is dropped (with a warning) when `maxAge` is 0, because a response that is stale on arrival yet
|
|
310
|
+
* promises never to change is a contradiction. Dropping it fails safe: the misconfiguration costs a revalidation,
|
|
311
|
+
* not a year of unreachable assets.
|
|
312
|
+
*
|
|
313
|
+
* @method
|
|
314
|
+
* @static
|
|
315
|
+
* @param {SettingsStaticCache} [staticCache] The configured block, if any.
|
|
316
|
+
* @returns {{maxAge: number, immutable: boolean, immutablePaths: string[], warnings: string[]}}
|
|
317
|
+
* @public
|
|
318
|
+
*/
|
|
319
|
+
static resolveStaticCachePolicy(staticCache?: SettingsStaticCache): {
|
|
320
|
+
maxAge: number;
|
|
321
|
+
immutable: boolean;
|
|
322
|
+
immutablePaths: string[];
|
|
323
|
+
warnings: string[];
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* Builds the `Cache-Control` value for one static file: the long-lived immutable policy when its served path sits
|
|
327
|
+
* under a configured `immutablePaths` prefix (matched case-sensitively, so a case mismatch falls back to the safe
|
|
328
|
+
* side), otherwise the policy's own `maxAge`/`immutable`. A `maxAge` of 0 is emitted as an explicit
|
|
329
|
+
* `must-revalidate` rather than a bare `max-age=0`, matching what the sibling `web-content` package serves.
|
|
330
|
+
* Pure and static; exposed for unit testing — not part of the customization surface.
|
|
331
|
+
*
|
|
332
|
+
* @method
|
|
333
|
+
* @static
|
|
334
|
+
* @param {string} rootPath The directory this `/static` mount serves.
|
|
335
|
+
* @param {string} filePath The absolute path of the file being served.
|
|
336
|
+
* @param {Object} policy A policy as returned by {@link TiWebServer.resolveStaticCachePolicy}.
|
|
337
|
+
* @returns {string}
|
|
338
|
+
* @public
|
|
339
|
+
*/
|
|
340
|
+
static staticCacheControlFor(rootPath: string, filePath: string, policy: Object): string;
|
|
341
|
+
/**
|
|
342
|
+
* Normalizes an HTTP method to a lower-case Express routing verb, or returns null if it is not a supported,
|
|
343
|
+
* registrable verb. Anything that is not a string is rejected outright rather than coerced — otherwise a value
|
|
344
|
+
* whose `toString()` happens to yield a verb (`[ "get" ]`, `new String( "get" )`) would register a route and
|
|
345
|
+
* bypass the `E_GEN_INVALID_ARGUMENT_TYPE` that {@link TiWebServer#registerRoute} raises for a bad method.
|
|
346
|
+
* Pure and static; exposed for unit testing — not part of the customization surface.
|
|
347
|
+
*
|
|
348
|
+
* @method
|
|
349
|
+
* @static
|
|
350
|
+
* @param {string} method
|
|
351
|
+
* @returns {string|null}
|
|
352
|
+
* @public
|
|
353
|
+
*/
|
|
354
|
+
static normalizeRegistrableMethod(method: string): string | null;
|
|
355
|
+
/**
|
|
356
|
+
* Tests a request path against a list of unprotected-route patterns (string exact-match or RegExp test),
|
|
357
|
+
* returning true on the first match. A RegExp's `lastIndex` is reset defensively so a stateful 'g'/'y' flag
|
|
358
|
+
* cannot cause a match to be skipped. Pure and static; shared by {@link TiWebServer#isUnprotectedRoute} and
|
|
359
|
+
* exposed for unit testing — not part of the customization surface.
|
|
360
|
+
*
|
|
361
|
+
* @method
|
|
362
|
+
* @static
|
|
363
|
+
* @param {Array<string|RegExp>} patterns
|
|
364
|
+
* @param {string} pathOnly The request path with any query string already stripped.
|
|
365
|
+
* @returns {boolean}
|
|
366
|
+
* @public
|
|
367
|
+
*/
|
|
368
|
+
static isRouteInList(patterns: Array<string | RegExp>, pathOnly: string): boolean;
|
|
369
|
+
}
|
|
370
|
+
declare namespace TiWebServer {
|
|
371
|
+
export { RE_STATIC_UNPROTECTED };
|
|
372
|
+
export { RE_WELL_KNOWN_UNPROTECTED };
|
|
373
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare var listEditors: (service: ConfigService) => ExpressHandler;
|
|
2
|
+
export declare var composeView: (service: any) => (request: any, response: any, next: any) => void;
|
|
3
|
+
export declare var saveEditorEdit: (service: any) => (request: any, response: any, next: any) => void;
|
|
4
|
+
export declare var getCurrent: (service: any) => (request: any, response: any, next: any) => void;
|
|
5
|
+
export declare var getHistory: (service: any) => (request: any, response: any, next: any) => void;
|
|
6
|
+
export declare var listChanges: (service: any) => (request: any, response: any, next: any) => void;
|
|
7
|
+
export declare var getChange: (service: any) => (request: any, response: any, next: any) => void;
|
|
8
|
+
export declare var restoreChangeSet: (service: any) => (request: any, response: any, next: any) => void;
|
|
9
|
+
export declare var exportBundle: (service: any) => (request: any, response: any, next: any) => void;
|
|
10
|
+
import type ConfigService from "#config-service";
|
|
11
|
+
import type { ExpressHandler } from "#web-handlers";
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export = AuthManager;
|
|
2
|
+
import User = require("#user");
|
|
3
|
+
import type { SettingsAuth } from "#web-server";
|
|
4
|
+
export type TiAuthMethod = string;
|
|
5
|
+
/** @import { SettingsAuth } from "#web-server" */
|
|
6
|
+
/**
|
|
7
|
+
* Enum for specifying the authentication method.
|
|
8
|
+
*
|
|
9
|
+
* @readonly
|
|
10
|
+
* @enum {string}
|
|
11
|
+
* @typedef {string} TiAuthMethod
|
|
12
|
+
*/
|
|
13
|
+
declare const authMethodEnum: import("@ti-engine/core/definitions").TiEnumOf<{
|
|
14
|
+
LOCAL: string[];
|
|
15
|
+
OPENID_AZURE: string[];
|
|
16
|
+
OPENID_GOOGLE: string[];
|
|
17
|
+
}>;
|
|
18
|
+
export type TiTokenEndpointAuthMethod = string;
|
|
19
|
+
/**
|
|
20
|
+
* The AuthManager class is used to manage authentication and authorization.
|
|
21
|
+
*
|
|
22
|
+
* @class AuthManager
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
declare class AuthManager {
|
|
26
|
+
#private;
|
|
27
|
+
/**
|
|
28
|
+
* @constructor
|
|
29
|
+
* @param {SettingsAuth} settings
|
|
30
|
+
*/
|
|
31
|
+
constructor(settings: SettingsAuth);
|
|
32
|
+
/**
|
|
33
|
+
* Used to initialize the authentication manager.
|
|
34
|
+
*
|
|
35
|
+
* @method
|
|
36
|
+
* @returns {Promise}
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
initialize(): Promise<any>;
|
|
40
|
+
/**
|
|
41
|
+
* Used to check whether the specified authentication method is enabled.
|
|
42
|
+
*
|
|
43
|
+
* @method
|
|
44
|
+
* @param {TiAuthMethod} authMethod
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
isAuthEnabled(authMethod: TiAuthMethod): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the list of currently enabled authentication methods, reflecting any OpenID providers dropped by
|
|
51
|
+
* {@link AuthManager#initialize} for being enabled but unconfigured. Callers (e.g. the login-page renderer)
|
|
52
|
+
* use this to present only the methods a user can actually complete.
|
|
53
|
+
*
|
|
54
|
+
* @method
|
|
55
|
+
* @returns {TiAuthMethod[]}
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
getEnabledMethods(): TiAuthMethod[];
|
|
59
|
+
/**
|
|
60
|
+
* Used to authenticate a user via the specified authentication method.
|
|
61
|
+
*
|
|
62
|
+
* @method
|
|
63
|
+
* @param {TiAuthMethod} authMethod
|
|
64
|
+
* @param {Object} authDetails
|
|
65
|
+
* @returns {Promise<Object>}
|
|
66
|
+
* @throws {TiException.E_SEC_UNRECOGNIZED_AUTH_METHOD} If the authentication method is not recognized or enabled.
|
|
67
|
+
* @throws {TiException.E_GEN_NOT_INITIALIZED} If the auth manager was not properly initialized.
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
authenticate(authMethod: TiAuthMethod, authDetails: Object): Promise<Object>;
|
|
71
|
+
/**
|
|
72
|
+
* Used to set up user authorization according to the specified authentication method.
|
|
73
|
+
*
|
|
74
|
+
* @method
|
|
75
|
+
* @param {TiAuthMethod} authMethod
|
|
76
|
+
* @param {URL} currentUrl
|
|
77
|
+
* @param {Object} oidc
|
|
78
|
+
* @returns {Promise<User>}
|
|
79
|
+
* @throws {TiException.E_SEC_UNRECOGNIZED_AUTH_METHOD} If the authentication method is not recognized.
|
|
80
|
+
* @public
|
|
81
|
+
*/
|
|
82
|
+
authorize(authMethod: TiAuthMethod, currentUrl: URL, oidc: Object): Promise<User>;
|
|
83
|
+
/**
|
|
84
|
+
* Used to get the callback URL for the specified OAuth2 authentication method.
|
|
85
|
+
*
|
|
86
|
+
* @method
|
|
87
|
+
* @param {TiAuthMethod} authMethod
|
|
88
|
+
* @returns {string}
|
|
89
|
+
* @throws {TiException.E_SEC_UNRECOGNIZED_AUTH_METHOD} If the requested OAuth2 method is not recognized or enabled.
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
getOAuth2CallbackUrl(authMethod: TiAuthMethod): string;
|
|
93
|
+
/**
|
|
94
|
+
* Used to get the local route path of the callback for the specified OAuth2 authentication method.
|
|
95
|
+
* <br/>
|
|
96
|
+
* A callback can legitimately be configured either as a path or as the full absolute URL registered with the
|
|
97
|
+
* identity provider. The absolute form is what the provider expects as the redirect URI, but it is not a usable
|
|
98
|
+
* Express route pattern, so this reduces whatever is configured to the path the server must actually listen on.
|
|
99
|
+
*
|
|
100
|
+
* @method
|
|
101
|
+
* @param {TiAuthMethod} authMethod
|
|
102
|
+
* @returns {string|null} The route path, or null if the configured callback yields no usable path.
|
|
103
|
+
* @throws {TiException.E_SEC_UNRECOGNIZED_AUTH_METHOD} If the requested OAuth2 method is not recognized or enabled.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
getOAuth2CallbackPath(authMethod: TiAuthMethod): string | null;
|
|
107
|
+
/**
|
|
108
|
+
* Reduces a configured OAuth2 callback value to the local route path it corresponds to. Accepts an absolute URL
|
|
109
|
+
* ('https://host/login/azure-callback'), a protocol-relative URL, or a path with or without its leading slash,
|
|
110
|
+
* and strips any query string or fragment. Pure and static; exposed for unit testing.
|
|
111
|
+
* <br/>
|
|
112
|
+
* NOTE: This exists because Express 5 parses a route pattern with path-to-regexp v8, where ':' opens a parameter
|
|
113
|
+
* name — so an absolute URL used verbatim as a route path throws 'Missing parameter name' at startup.
|
|
114
|
+
*
|
|
115
|
+
* @method
|
|
116
|
+
* @static
|
|
117
|
+
* @param {string} callbackUrl
|
|
118
|
+
* @returns {string|null} The route path, or null if no usable path can be derived.
|
|
119
|
+
* @public
|
|
120
|
+
*/
|
|
121
|
+
static toCallbackPath(callbackUrl: string): string | null;
|
|
122
|
+
}
|
|
123
|
+
declare namespace AuthManager {
|
|
124
|
+
export { authMethodEnum as authMethod };
|
|
125
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
declare const _exports: {
|
|
2
|
+
ADMIN_ROLE: string;
|
|
3
|
+
isAdminIdentity: typeof isAdminIdentity;
|
|
4
|
+
applyAdminRole: typeof applyAdminRole;
|
|
5
|
+
hasAnyRole: typeof hasAnyRole;
|
|
6
|
+
isAccessAllowed: typeof isAccessAllowed;
|
|
7
|
+
requireRole: typeof requireRole;
|
|
8
|
+
requireAdmin: (request: Object, response: Object, next: Function) => void;
|
|
9
|
+
};
|
|
10
|
+
export = _exports;
|
|
11
|
+
/**
|
|
12
|
+
* Returns `true` if the user matches any entry in the admin allowlist. An entry may match the user's `userID`,
|
|
13
|
+
* `username`, or `email` (case-insensitive).
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} user A session user (`{ userID, username, email, roles, ... }`).
|
|
16
|
+
* @param {string[]} admins The configured allowlist of admin identifiers.
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
declare function isAdminIdentity(user: Object, admins: string[]): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Adds the `admin` role to the session user (additively, no duplicates) when the user is in the allowlist.
|
|
22
|
+
* Safe to call with an empty/missing allowlist or session — it is then a no-op. Returns the session for chaining.
|
|
23
|
+
*
|
|
24
|
+
* @param {Object} session
|
|
25
|
+
* @param {string[]} [admins]
|
|
26
|
+
* @returns {Object} The (possibly modified) session.
|
|
27
|
+
*/
|
|
28
|
+
declare function applyAdminRole(session: Object, admins?: string[]): Object;
|
|
29
|
+
/**
|
|
30
|
+
* @param {Object} session
|
|
31
|
+
* @param {Array<string|number>} roles
|
|
32
|
+
* @returns {boolean} `true` if the session user holds any of the given roles.
|
|
33
|
+
*/
|
|
34
|
+
declare function hasAnyRole(session: Object, roles: Array<string | number>): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Pure access decision for a resource (e.g. an HTML fragment) that declares a set of required roles. A resource with
|
|
37
|
+
* no required roles (`null` / `undefined` / empty) is public — any (authenticated) user may access it; otherwise the
|
|
38
|
+
* user must hold at least one of the required roles. Roles are treated opaquely, so this works equally for numeric
|
|
39
|
+
* application role codes and the string `admin` role — there is no implicit hierarchy (an `admin`-gated resource is
|
|
40
|
+
* reachable only by holders of the `admin` role, never by a high numeric role). Backs {@link TiWebAppManager#verifyAccess}.
|
|
41
|
+
*
|
|
42
|
+
* @param {Array<string|number>} [requiredRoles] The roles permitted to access the resource; empty/absent = public.
|
|
43
|
+
* @param {Array<string|number>} [userRoles] The roles held by the current session user.
|
|
44
|
+
* @returns {boolean}
|
|
45
|
+
*/
|
|
46
|
+
declare function isAccessAllowed(requiredRoles?: Array<string | number>, userRoles?: Array<string | number>): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Express middleware factory that admits a request only if its session user holds at least one of the given roles.
|
|
49
|
+
* Responds `401` when unauthenticated (no session user) and `403` when authenticated but lacking the role.
|
|
50
|
+
*
|
|
51
|
+
* @param {...(string|number)} roles
|
|
52
|
+
* @returns {(request: Object, response: Object, next: Function) => void}
|
|
53
|
+
*/
|
|
54
|
+
declare function requireRole(...roles: (string | number)[]): (request: Object, response: Object, next: Function) => void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export = ConfigChangeNotifier;
|
|
2
|
+
export type ConfigChangeEvent = {
|
|
3
|
+
changeSetID: string;
|
|
4
|
+
/**
|
|
5
|
+
* The configuration documents affected by the change.
|
|
6
|
+
*/
|
|
7
|
+
configKeys: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Who committed the change.
|
|
10
|
+
*/
|
|
11
|
+
adminID: string;
|
|
12
|
+
/**
|
|
13
|
+
* ISO timestamp.
|
|
14
|
+
*/
|
|
15
|
+
timestamp: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} ConfigChangeEvent
|
|
19
|
+
* @property {string} changeSetID
|
|
20
|
+
* @property {string[]} configKeys The configuration documents affected by the change.
|
|
21
|
+
* @property {string} adminID Who committed the change.
|
|
22
|
+
* @property {string} timestamp ISO timestamp.
|
|
23
|
+
*/
|
|
24
|
+
declare const CONFIG_CHANGED = "config:changed";
|
|
25
|
+
/**
|
|
26
|
+
* Notifies subscribers that configuration changed, so they can react (e.g. invalidate an in-memory cache, or push a
|
|
27
|
+
* live update to an admin UI). This is the **in-process** implementation of a deliberately transport-agnostic
|
|
28
|
+
* contract — `publish(event)` (fire-and-forget) and `subscribe(listener) → unsubscribe`.
|
|
29
|
+
*
|
|
30
|
+
* **Designed for an eventual switch to a reusable core pub/sub.** Cross-instance propagation is out of scope for v1
|
|
31
|
+
* (the store-backed model already makes a committed change visible to every instance via the shared Redis cache;
|
|
32
|
+
* this emitter exists to invalidate optional *in-memory* caches and drive live UI within a process). When a Redis
|
|
33
|
+
* (or other) pub/sub primitive lands in `@ti-engine/core`, a drop-in implementation of this same contract can be
|
|
34
|
+
* provided and injected into {@link ConfigService} — no change to publishers or subscribers. To keep that swap
|
|
35
|
+
* behavior-safe, **delivery here is already asynchronous** (matching cross-instance transports); subscribers must
|
|
36
|
+
* not assume synchronous delivery, and the event payload is plain serializable JSON so it survives a wire transport.
|
|
37
|
+
*
|
|
38
|
+
* @class ConfigChangeNotifier
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
declare class ConfigChangeNotifier {
|
|
42
|
+
#private;
|
|
43
|
+
constructor();
|
|
44
|
+
/**
|
|
45
|
+
* Publishes a configuration-change event to all subscribers. Fire-and-forget; delivery is asynchronous.
|
|
46
|
+
*
|
|
47
|
+
* @method
|
|
48
|
+
* @param {ConfigChangeEvent} event
|
|
49
|
+
* @returns {ConfigChangeEvent} The (frozen) event that will be delivered.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
publish(event: ConfigChangeEvent): ConfigChangeEvent;
|
|
53
|
+
/**
|
|
54
|
+
* Subscribes a listener to configuration-change events.
|
|
55
|
+
*
|
|
56
|
+
* @method
|
|
57
|
+
* @param {(event: ConfigChangeEvent) => void} listener
|
|
58
|
+
* @returns {() => void} An unsubscribe function.
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
subscribe(listener: (event: ConfigChangeEvent) => void): () => void;
|
|
62
|
+
/**
|
|
63
|
+
* @method
|
|
64
|
+
* @returns {number} The current number of subscribers.
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
subscriberCount(): number;
|
|
68
|
+
}
|
|
69
|
+
declare namespace ConfigChangeNotifier {
|
|
70
|
+
export { instance };
|
|
71
|
+
export { CONFIG_CHANGED };
|
|
72
|
+
}
|
|
73
|
+
declare const instance: ConfigChangeNotifier;
|