digitaltwin-core 0.14.2 → 1.0.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/LICENSE +20 -20
- package/README.md +494 -359
- package/dist/auth/apisix_parser.d.ts +141 -0
- package/dist/auth/apisix_parser.d.ts.map +1 -0
- package/dist/auth/apisix_parser.js +161 -0
- package/dist/auth/apisix_parser.js.map +1 -0
- package/dist/auth/auth_config.d.ts +126 -0
- package/dist/auth/auth_config.d.ts.map +1 -0
- package/dist/auth/auth_config.js +169 -0
- package/dist/auth/auth_config.js.map +1 -0
- package/dist/auth/auth_provider.d.ts +118 -0
- package/dist/auth/auth_provider.d.ts.map +1 -0
- package/dist/auth/auth_provider.js +8 -0
- package/dist/auth/auth_provider.js.map +1 -0
- package/dist/auth/auth_provider_factory.d.ts +91 -0
- package/dist/auth/auth_provider_factory.d.ts.map +1 -0
- package/dist/auth/auth_provider_factory.js +146 -0
- package/dist/auth/auth_provider_factory.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts +78 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.js +109 -0
- package/dist/auth/providers/gateway_auth_provider.js.map +1 -0
- package/dist/auth/providers/index.d.ts +4 -0
- package/dist/auth/providers/index.d.ts.map +1 -0
- package/dist/auth/providers/index.js +4 -0
- package/dist/auth/providers/index.js.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts +91 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.js +204 -0
- package/dist/auth/providers/jwt_auth_provider.js.map +1 -0
- package/dist/auth/providers/no_auth_provider.d.ts +61 -0
- package/dist/auth/providers/no_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/no_auth_provider.js +76 -0
- package/dist/auth/providers/no_auth_provider.js.map +1 -0
- package/dist/auth/types.d.ts +100 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/user_service.d.ts +86 -0
- package/dist/auth/user_service.d.ts.map +1 -0
- package/dist/auth/user_service.js +237 -0
- package/dist/auth/user_service.js.map +1 -0
- package/dist/components/assets_manager.d.ts +662 -0
- package/dist/components/assets_manager.d.ts.map +1 -0
- package/dist/components/assets_manager.js +1537 -0
- package/dist/components/assets_manager.js.map +1 -0
- package/dist/components/async_upload.d.ts +20 -0
- package/dist/components/async_upload.d.ts.map +1 -0
- package/dist/components/async_upload.js +10 -0
- package/dist/components/async_upload.js.map +1 -0
- package/dist/components/collector.d.ts +203 -0
- package/dist/components/collector.d.ts.map +1 -0
- package/dist/components/collector.js +214 -0
- package/dist/components/collector.js.map +1 -0
- package/dist/components/custom_table_manager.d.ts +503 -0
- package/dist/components/custom_table_manager.d.ts.map +1 -0
- package/dist/components/custom_table_manager.js +1023 -0
- package/dist/components/custom_table_manager.js.map +1 -0
- package/dist/components/global_assets_handler.d.ts +63 -0
- package/dist/components/global_assets_handler.d.ts.map +1 -0
- package/dist/components/global_assets_handler.js +127 -0
- package/dist/components/global_assets_handler.js.map +1 -0
- package/dist/components/handler.d.ts +104 -0
- package/dist/components/handler.d.ts.map +1 -0
- package/dist/components/handler.js +110 -0
- package/dist/components/handler.js.map +1 -0
- package/dist/components/harvester.d.ts +182 -0
- package/dist/components/harvester.d.ts.map +1 -0
- package/dist/components/harvester.js +406 -0
- package/dist/components/harvester.js.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +9 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/interfaces.d.ts +126 -0
- package/dist/components/interfaces.d.ts.map +1 -0
- package/dist/components/interfaces.js +8 -0
- package/dist/components/interfaces.js.map +1 -0
- package/dist/components/map_manager.d.ts +61 -0
- package/dist/components/map_manager.d.ts.map +1 -0
- package/dist/components/map_manager.js +242 -0
- package/dist/components/map_manager.js.map +1 -0
- package/dist/components/tileset_manager.d.ts +125 -0
- package/dist/components/tileset_manager.d.ts.map +1 -0
- package/dist/components/tileset_manager.js +623 -0
- package/dist/components/tileset_manager.js.map +1 -0
- package/dist/components/types.d.ts +226 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +8 -0
- package/dist/components/types.js.map +1 -0
- package/dist/database/adapters/knex_database_adapter.d.ts +97 -0
- package/dist/database/adapters/knex_database_adapter.d.ts.map +1 -0
- package/dist/database/adapters/knex_database_adapter.js +729 -0
- package/dist/database/adapters/knex_database_adapter.js.map +1 -0
- package/dist/database/database_adapter.d.ts +262 -0
- package/dist/database/database_adapter.d.ts.map +1 -0
- package/dist/database/database_adapter.js +46 -0
- package/dist/database/database_adapter.js.map +1 -0
- package/dist/engine/digital_twin_engine.d.ts +295 -0
- package/dist/engine/digital_twin_engine.d.ts.map +1 -0
- package/dist/engine/digital_twin_engine.js +907 -0
- package/dist/engine/digital_twin_engine.js.map +1 -0
- package/dist/engine/endpoints.d.ts +47 -0
- package/dist/engine/endpoints.d.ts.map +1 -0
- package/dist/engine/endpoints.js +88 -0
- package/dist/engine/endpoints.js.map +1 -0
- package/dist/engine/error_handler.d.ts +20 -0
- package/dist/engine/error_handler.d.ts.map +1 -0
- package/dist/engine/error_handler.js +69 -0
- package/dist/engine/error_handler.js.map +1 -0
- package/dist/engine/events.d.ts +93 -0
- package/dist/engine/events.d.ts.map +1 -0
- package/dist/engine/events.js +71 -0
- package/dist/engine/events.js.map +1 -0
- package/dist/engine/health.d.ts +112 -0
- package/dist/engine/health.d.ts.map +1 -0
- package/dist/engine/health.js +190 -0
- package/dist/engine/health.js.map +1 -0
- package/dist/engine/initializer.d.ts +62 -0
- package/dist/engine/initializer.d.ts.map +1 -0
- package/dist/engine/initializer.js +108 -0
- package/dist/engine/initializer.js.map +1 -0
- package/dist/engine/queue_manager.d.ts +87 -0
- package/dist/engine/queue_manager.d.ts.map +1 -0
- package/dist/engine/queue_manager.js +196 -0
- package/dist/engine/queue_manager.js.map +1 -0
- package/dist/engine/scheduler.d.ts +30 -0
- package/dist/engine/scheduler.d.ts.map +1 -0
- package/dist/engine/scheduler.js +378 -0
- package/dist/engine/scheduler.js.map +1 -0
- package/dist/engine/upload_processor.d.ts +36 -0
- package/dist/engine/upload_processor.d.ts.map +1 -0
- package/dist/engine/upload_processor.js +113 -0
- package/dist/engine/upload_processor.js.map +1 -0
- package/dist/env/env.d.ts +134 -0
- package/dist/env/env.d.ts.map +1 -0
- package/dist/env/env.js +177 -0
- package/dist/env/env.js.map +1 -0
- package/dist/errors/index.d.ts +94 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +149 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/openapi/generator.d.ts +93 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +293 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/openapi/index.d.ts +9 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +9 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/types.d.ts +182 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi/types.js +16 -0
- package/dist/openapi/types.js.map +1 -0
- package/dist/storage/adapters/local_storage_service.d.ts +57 -0
- package/dist/storage/adapters/local_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/local_storage_service.js +132 -0
- package/dist/storage/adapters/local_storage_service.js.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts +72 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.js +205 -0
- package/dist/storage/adapters/ovh_storage_service.js.map +1 -0
- package/dist/storage/storage_factory.d.ts +14 -0
- package/dist/storage/storage_factory.d.ts.map +1 -0
- package/dist/storage/storage_factory.js +43 -0
- package/dist/storage/storage_factory.js.map +1 -0
- package/dist/storage/storage_service.d.ts +163 -0
- package/dist/storage/storage_service.d.ts.map +1 -0
- package/dist/storage/storage_service.js +58 -0
- package/dist/storage/storage_service.js.map +1 -0
- package/dist/types/data_record.d.ts +123 -0
- package/dist/types/data_record.d.ts.map +1 -0
- package/dist/types/data_record.js +8 -0
- package/dist/types/data_record.js.map +1 -0
- package/dist/utils/graceful_shutdown.d.ts +44 -0
- package/dist/utils/graceful_shutdown.d.ts.map +1 -0
- package/dist/utils/graceful_shutdown.js +79 -0
- package/dist/utils/graceful_shutdown.js.map +1 -0
- package/dist/utils/http_responses.d.ts +175 -0
- package/dist/utils/http_responses.d.ts.map +1 -0
- package/dist/utils/http_responses.js +216 -0
- package/dist/utils/http_responses.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +74 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +92 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/map_to_data_record.d.ts +10 -0
- package/dist/utils/map_to_data_record.d.ts.map +1 -0
- package/dist/utils/map_to_data_record.js +36 -0
- package/dist/utils/map_to_data_record.js.map +1 -0
- package/dist/utils/safe_async.d.ts +50 -0
- package/dist/utils/safe_async.d.ts.map +1 -0
- package/dist/utils/safe_async.js +90 -0
- package/dist/utils/safe_async.js.map +1 -0
- package/dist/utils/servable_endpoint.d.ts +63 -0
- package/dist/utils/servable_endpoint.d.ts.map +1 -0
- package/dist/utils/servable_endpoint.js +67 -0
- package/dist/utils/servable_endpoint.js.map +1 -0
- package/dist/utils/zip_utils.d.ts +66 -0
- package/dist/utils/zip_utils.d.ts.map +1 -0
- package/dist/utils/zip_utils.js +169 -0
- package/dist/utils/zip_utils.js.map +1 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.d.ts +273 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +82 -0
- package/dist/validation/schemas.js.map +1 -0
- package/dist/validation/validate.d.ts +49 -0
- package/dist/validation/validate.d.ts.map +1 -0
- package/dist/validation/validate.js +110 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +23 -13
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview JWT authentication provider for direct token validation.
|
|
3
|
+
*
|
|
4
|
+
* This provider validates JWT tokens from the Authorization header without
|
|
5
|
+
* requiring an API gateway. Useful for standalone deployments or when you
|
|
6
|
+
* want to handle authentication directly in the application.
|
|
7
|
+
*
|
|
8
|
+
* Supports:
|
|
9
|
+
* - HMAC algorithms (HS256, HS384, HS512) with a secret key
|
|
10
|
+
* - RSA algorithms (RS256, RS384, RS512) with a public key
|
|
11
|
+
* - EC algorithms (ES256, ES384, ES512) with a public key
|
|
12
|
+
* - Keycloak token format (realm_access.roles)
|
|
13
|
+
* - Custom claim paths for user ID and roles
|
|
14
|
+
*/
|
|
15
|
+
import type { AuthProvider, AuthRequest, AuthProviderConfig } from '../auth_provider.js';
|
|
16
|
+
import type { AuthenticatedUser } from '../types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Authentication provider for JWT token validation.
|
|
19
|
+
*
|
|
20
|
+
* This provider validates JWT tokens directly in the application, without
|
|
21
|
+
* requiring an API gateway. It extracts user information from token claims.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // With HMAC secret
|
|
26
|
+
* const provider = new JwtAuthProvider({
|
|
27
|
+
* mode: 'jwt',
|
|
28
|
+
* jwt: {
|
|
29
|
+
* secret: 'your-256-bit-secret',
|
|
30
|
+
* algorithm: 'HS256'
|
|
31
|
+
* }
|
|
32
|
+
* })
|
|
33
|
+
*
|
|
34
|
+
* // With RSA public key (Keycloak)
|
|
35
|
+
* const provider = new JwtAuthProvider({
|
|
36
|
+
* mode: 'jwt',
|
|
37
|
+
* jwt: {
|
|
38
|
+
* publicKey: fs.readFileSync('public.pem', 'utf-8'),
|
|
39
|
+
* algorithm: 'RS256',
|
|
40
|
+
* issuer: 'https://keycloak.example.com/realms/myrealm',
|
|
41
|
+
* rolesClaim: 'realm_access.roles'
|
|
42
|
+
* }
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class JwtAuthProvider implements AuthProvider {
|
|
47
|
+
#private;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new JwtAuthProvider.
|
|
50
|
+
*
|
|
51
|
+
* @param config - Authentication configuration with JWT settings
|
|
52
|
+
* @throws Error if JWT configuration is missing or incomplete
|
|
53
|
+
*/
|
|
54
|
+
constructor(config: AuthProviderConfig);
|
|
55
|
+
/**
|
|
56
|
+
* Parse the request and validate the JWT token.
|
|
57
|
+
*
|
|
58
|
+
* @param req - Request object with headers
|
|
59
|
+
* @returns Authenticated user, or null if token is missing/invalid
|
|
60
|
+
*/
|
|
61
|
+
parseRequest(req: AuthRequest): AuthenticatedUser | null;
|
|
62
|
+
/**
|
|
63
|
+
* Check if the request has a valid Authorization header with Bearer token.
|
|
64
|
+
*
|
|
65
|
+
* @param req - Request object with headers
|
|
66
|
+
* @returns true if Authorization header is present with Bearer scheme
|
|
67
|
+
*/
|
|
68
|
+
hasValidAuth(req: AuthRequest): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if the authenticated user has admin privileges.
|
|
71
|
+
*
|
|
72
|
+
* @param req - Request object with headers
|
|
73
|
+
* @returns true if the user has the admin role
|
|
74
|
+
*/
|
|
75
|
+
isAdmin(req: AuthRequest): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get the user ID from the JWT token.
|
|
78
|
+
*
|
|
79
|
+
* @param req - Request object with headers
|
|
80
|
+
* @returns User ID, or null if not authenticated
|
|
81
|
+
*/
|
|
82
|
+
getUserId(req: AuthRequest): string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Get the user roles from the JWT token.
|
|
85
|
+
*
|
|
86
|
+
* @param req - Request object with headers
|
|
87
|
+
* @returns Array of role names, empty array if not authenticated
|
|
88
|
+
*/
|
|
89
|
+
getUserRoles(req: AuthRequest): string[];
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=jwt_auth_provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt_auth_provider.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/jwt_auth_provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,eAAgB,YAAW,YAAY;;IAShD;;;;;OAKG;gBACS,MAAM,EAAE,kBAAkB;IAwBtC;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,iBAAiB,GAAG,IAAI;IAuBxD;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO;IAIvC;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO;IAKlC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAK1C;;;;;OAKG;IACH,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,EAAE;CAkE3C"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview JWT authentication provider for direct token validation.
|
|
3
|
+
*
|
|
4
|
+
* This provider validates JWT tokens from the Authorization header without
|
|
5
|
+
* requiring an API gateway. Useful for standalone deployments or when you
|
|
6
|
+
* want to handle authentication directly in the application.
|
|
7
|
+
*
|
|
8
|
+
* Supports:
|
|
9
|
+
* - HMAC algorithms (HS256, HS384, HS512) with a secret key
|
|
10
|
+
* - RSA algorithms (RS256, RS384, RS512) with a public key
|
|
11
|
+
* - EC algorithms (ES256, ES384, ES512) with a public key
|
|
12
|
+
* - Keycloak token format (realm_access.roles)
|
|
13
|
+
* - Custom claim paths for user ID and roles
|
|
14
|
+
*/
|
|
15
|
+
import jwt from 'jsonwebtoken';
|
|
16
|
+
/**
|
|
17
|
+
* Authentication provider for JWT token validation.
|
|
18
|
+
*
|
|
19
|
+
* This provider validates JWT tokens directly in the application, without
|
|
20
|
+
* requiring an API gateway. It extracts user information from token claims.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // With HMAC secret
|
|
25
|
+
* const provider = new JwtAuthProvider({
|
|
26
|
+
* mode: 'jwt',
|
|
27
|
+
* jwt: {
|
|
28
|
+
* secret: 'your-256-bit-secret',
|
|
29
|
+
* algorithm: 'HS256'
|
|
30
|
+
* }
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* // With RSA public key (Keycloak)
|
|
34
|
+
* const provider = new JwtAuthProvider({
|
|
35
|
+
* mode: 'jwt',
|
|
36
|
+
* jwt: {
|
|
37
|
+
* publicKey: fs.readFileSync('public.pem', 'utf-8'),
|
|
38
|
+
* algorithm: 'RS256',
|
|
39
|
+
* issuer: 'https://keycloak.example.com/realms/myrealm',
|
|
40
|
+
* rolesClaim: 'realm_access.roles'
|
|
41
|
+
* }
|
|
42
|
+
* })
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class JwtAuthProvider {
|
|
46
|
+
#secret;
|
|
47
|
+
#algorithm;
|
|
48
|
+
#issuer;
|
|
49
|
+
#audience;
|
|
50
|
+
#userIdClaim;
|
|
51
|
+
#rolesClaim;
|
|
52
|
+
#adminRoleName;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new JwtAuthProvider.
|
|
55
|
+
*
|
|
56
|
+
* @param config - Authentication configuration with JWT settings
|
|
57
|
+
* @throws Error if JWT configuration is missing or incomplete
|
|
58
|
+
*/
|
|
59
|
+
constructor(config) {
|
|
60
|
+
if (!config.jwt) {
|
|
61
|
+
throw new Error('JWT configuration required for JWT auth mode');
|
|
62
|
+
}
|
|
63
|
+
const { jwt: jwtConfig } = config;
|
|
64
|
+
// Secret or public key
|
|
65
|
+
if (jwtConfig.publicKey) {
|
|
66
|
+
this.#secret = jwtConfig.publicKey;
|
|
67
|
+
}
|
|
68
|
+
else if (jwtConfig.secret) {
|
|
69
|
+
this.#secret = jwtConfig.secret;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error('JWT secret or publicKey required');
|
|
73
|
+
}
|
|
74
|
+
this.#algorithm = jwtConfig.algorithm || 'HS256';
|
|
75
|
+
this.#issuer = jwtConfig.issuer;
|
|
76
|
+
this.#audience = jwtConfig.audience;
|
|
77
|
+
this.#userIdClaim = jwtConfig.userIdClaim || 'sub';
|
|
78
|
+
this.#rolesClaim = jwtConfig.rolesClaim || 'roles';
|
|
79
|
+
this.#adminRoleName = config.adminRoleName || 'admin';
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parse the request and validate the JWT token.
|
|
83
|
+
*
|
|
84
|
+
* @param req - Request object with headers
|
|
85
|
+
* @returns Authenticated user, or null if token is missing/invalid
|
|
86
|
+
*/
|
|
87
|
+
parseRequest(req) {
|
|
88
|
+
const token = this.#extractToken(req);
|
|
89
|
+
if (!token)
|
|
90
|
+
return null;
|
|
91
|
+
try {
|
|
92
|
+
const decoded = jwt.verify(token, this.#secret, {
|
|
93
|
+
algorithms: [this.#algorithm],
|
|
94
|
+
issuer: this.#issuer,
|
|
95
|
+
audience: this.#audience
|
|
96
|
+
});
|
|
97
|
+
const userId = this.#extractClaim(decoded, this.#userIdClaim);
|
|
98
|
+
if (!userId || typeof userId !== 'string')
|
|
99
|
+
return null;
|
|
100
|
+
const roles = this.#extractRoles(decoded);
|
|
101
|
+
return { id: userId, roles };
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Token invalid or expired
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if the request has a valid Authorization header with Bearer token.
|
|
110
|
+
*
|
|
111
|
+
* @param req - Request object with headers
|
|
112
|
+
* @returns true if Authorization header is present with Bearer scheme
|
|
113
|
+
*/
|
|
114
|
+
hasValidAuth(req) {
|
|
115
|
+
return !!this.#extractToken(req);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if the authenticated user has admin privileges.
|
|
119
|
+
*
|
|
120
|
+
* @param req - Request object with headers
|
|
121
|
+
* @returns true if the user has the admin role
|
|
122
|
+
*/
|
|
123
|
+
isAdmin(req) {
|
|
124
|
+
const user = this.parseRequest(req);
|
|
125
|
+
return user?.roles.includes(this.#adminRoleName) ?? false;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the user ID from the JWT token.
|
|
129
|
+
*
|
|
130
|
+
* @param req - Request object with headers
|
|
131
|
+
* @returns User ID, or null if not authenticated
|
|
132
|
+
*/
|
|
133
|
+
getUserId(req) {
|
|
134
|
+
const user = this.parseRequest(req);
|
|
135
|
+
return user?.id ?? null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get the user roles from the JWT token.
|
|
139
|
+
*
|
|
140
|
+
* @param req - Request object with headers
|
|
141
|
+
* @returns Array of role names, empty array if not authenticated
|
|
142
|
+
*/
|
|
143
|
+
getUserRoles(req) {
|
|
144
|
+
const user = this.parseRequest(req);
|
|
145
|
+
return user?.roles ?? [];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extract the Bearer token from the Authorization header.
|
|
149
|
+
*/
|
|
150
|
+
#extractToken(req) {
|
|
151
|
+
const authHeader = this.#getHeader(req.headers, 'authorization');
|
|
152
|
+
if (!authHeader)
|
|
153
|
+
return null;
|
|
154
|
+
// Format: "Bearer <token>"
|
|
155
|
+
const parts = authHeader.split(' ');
|
|
156
|
+
if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
return parts[1];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extract a claim value from the token payload.
|
|
163
|
+
* Supports nested paths like "realm_access.roles".
|
|
164
|
+
*/
|
|
165
|
+
#extractClaim(payload, path) {
|
|
166
|
+
const parts = path.split('.');
|
|
167
|
+
let current = payload;
|
|
168
|
+
for (const part of parts) {
|
|
169
|
+
if (current === null || current === undefined)
|
|
170
|
+
return undefined;
|
|
171
|
+
if (typeof current !== 'object')
|
|
172
|
+
return undefined;
|
|
173
|
+
current = current[part];
|
|
174
|
+
}
|
|
175
|
+
return current;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Extract roles from the token payload.
|
|
179
|
+
* Supports standard array format and Keycloak's realm_access.roles.
|
|
180
|
+
*/
|
|
181
|
+
#extractRoles(payload) {
|
|
182
|
+
// Try configured roles claim first
|
|
183
|
+
const roles = this.#extractClaim(payload, this.#rolesClaim);
|
|
184
|
+
if (Array.isArray(roles)) {
|
|
185
|
+
return roles.filter((r) => typeof r === 'string');
|
|
186
|
+
}
|
|
187
|
+
// Fallback to Keycloak format
|
|
188
|
+
const realmAccess = payload.realm_access;
|
|
189
|
+
if (realmAccess?.roles && Array.isArray(realmAccess.roles)) {
|
|
190
|
+
return realmAccess.roles;
|
|
191
|
+
}
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get a header value as a string.
|
|
196
|
+
*/
|
|
197
|
+
#getHeader(headers, name) {
|
|
198
|
+
const value = headers[name];
|
|
199
|
+
if (!value)
|
|
200
|
+
return null;
|
|
201
|
+
return Array.isArray(value) ? value[0] : value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=jwt_auth_provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt_auth_provider.js","sourceRoot":"","sources":["../../../src/auth/providers/jwt_auth_provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No-authentication provider for development and testing.
|
|
3
|
+
*
|
|
4
|
+
* This provider bypasses all authentication checks and returns a configurable
|
|
5
|
+
* anonymous user for all requests. Use only in development or testing environments.
|
|
6
|
+
*
|
|
7
|
+
* WARNING: Never use this provider in production!
|
|
8
|
+
*/
|
|
9
|
+
import type { AuthProvider, AuthRequest } from '../auth_provider.js';
|
|
10
|
+
import type { AuthenticatedUser } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Authentication provider that bypasses authentication.
|
|
13
|
+
*
|
|
14
|
+
* All requests are treated as authenticated with a configurable anonymous user.
|
|
15
|
+
* This provider is useful for development and testing when you don't want to
|
|
16
|
+
* set up authentication infrastructure.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Development setup
|
|
21
|
+
* const provider = new NoAuthProvider('dev-user-123')
|
|
22
|
+
*
|
|
23
|
+
* // All requests return the same user
|
|
24
|
+
* const user = provider.parseRequest(req) // { id: 'dev-user-123', roles: ['user'] }
|
|
25
|
+
* provider.hasValidAuth(req) // always true
|
|
26
|
+
* provider.isAdmin(req) // always false
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class NoAuthProvider implements AuthProvider {
|
|
30
|
+
#private;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new NoAuthProvider.
|
|
33
|
+
*
|
|
34
|
+
* @param anonymousUserId - User ID for the anonymous user (default: 'anonymous')
|
|
35
|
+
* @param anonymousRoles - Roles for the anonymous user (default: ['anonymous'])
|
|
36
|
+
*/
|
|
37
|
+
constructor(anonymousUserId?: string, anonymousRoles?: string[]);
|
|
38
|
+
/**
|
|
39
|
+
* Returns the anonymous user for all requests.
|
|
40
|
+
*
|
|
41
|
+
* @returns Anonymous user with configured ID and roles
|
|
42
|
+
*/
|
|
43
|
+
parseRequest(_req: AuthRequest): AuthenticatedUser | null;
|
|
44
|
+
/**
|
|
45
|
+
* Always returns true (all requests are "authenticated").
|
|
46
|
+
*/
|
|
47
|
+
hasValidAuth(_req: AuthRequest): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Always returns false (anonymous user is never admin).
|
|
50
|
+
*/
|
|
51
|
+
isAdmin(_req: AuthRequest): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the anonymous user ID.
|
|
54
|
+
*/
|
|
55
|
+
getUserId(_req: AuthRequest): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Returns the anonymous user roles.
|
|
58
|
+
*/
|
|
59
|
+
getUserRoles(_req: AuthRequest): string[];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=no_auth_provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no_auth_provider.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/no_auth_provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,YAAW,YAAY;;IAI/C;;;;;OAKG;gBACS,eAAe,SAAc,EAAE,cAAc,GAAE,MAAM,EAAkB;IAKnF;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,iBAAiB,GAAG,IAAI;IAOzD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO;IAIxC;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO;IAInC;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAI3C;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE;CAG5C"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No-authentication provider for development and testing.
|
|
3
|
+
*
|
|
4
|
+
* This provider bypasses all authentication checks and returns a configurable
|
|
5
|
+
* anonymous user for all requests. Use only in development or testing environments.
|
|
6
|
+
*
|
|
7
|
+
* WARNING: Never use this provider in production!
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Authentication provider that bypasses authentication.
|
|
11
|
+
*
|
|
12
|
+
* All requests are treated as authenticated with a configurable anonymous user.
|
|
13
|
+
* This provider is useful for development and testing when you don't want to
|
|
14
|
+
* set up authentication infrastructure.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Development setup
|
|
19
|
+
* const provider = new NoAuthProvider('dev-user-123')
|
|
20
|
+
*
|
|
21
|
+
* // All requests return the same user
|
|
22
|
+
* const user = provider.parseRequest(req) // { id: 'dev-user-123', roles: ['user'] }
|
|
23
|
+
* provider.hasValidAuth(req) // always true
|
|
24
|
+
* provider.isAdmin(req) // always false
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class NoAuthProvider {
|
|
28
|
+
#anonymousUserId;
|
|
29
|
+
#anonymousRoles;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new NoAuthProvider.
|
|
32
|
+
*
|
|
33
|
+
* @param anonymousUserId - User ID for the anonymous user (default: 'anonymous')
|
|
34
|
+
* @param anonymousRoles - Roles for the anonymous user (default: ['anonymous'])
|
|
35
|
+
*/
|
|
36
|
+
constructor(anonymousUserId = 'anonymous', anonymousRoles = ['anonymous']) {
|
|
37
|
+
this.#anonymousUserId = anonymousUserId;
|
|
38
|
+
this.#anonymousRoles = anonymousRoles;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns the anonymous user for all requests.
|
|
42
|
+
*
|
|
43
|
+
* @returns Anonymous user with configured ID and roles
|
|
44
|
+
*/
|
|
45
|
+
parseRequest(_req) {
|
|
46
|
+
return {
|
|
47
|
+
id: this.#anonymousUserId,
|
|
48
|
+
roles: this.#anonymousRoles
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Always returns true (all requests are "authenticated").
|
|
53
|
+
*/
|
|
54
|
+
hasValidAuth(_req) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Always returns false (anonymous user is never admin).
|
|
59
|
+
*/
|
|
60
|
+
isAdmin(_req) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns the anonymous user ID.
|
|
65
|
+
*/
|
|
66
|
+
getUserId(_req) {
|
|
67
|
+
return this.#anonymousUserId;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Returns the anonymous user roles.
|
|
71
|
+
*/
|
|
72
|
+
getUserRoles(_req) {
|
|
73
|
+
return this.#anonymousRoles;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=no_auth_provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no_auth_provider.js","sourceRoot":"","sources":["../../../src/auth/providers/no_auth_provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,cAAc;IACd,gBAAgB,CAAQ;IACxB,eAAe,CAAU;IAElC;;;;;OAKG;IACH,YAAY,eAAe,GAAG,WAAW,EAAE,iBAA2B,CAAC,WAAW,CAAC;QAC/E,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAA;QACvC,IAAI,CAAC,eAAe,GAAG,cAAc,CAAA;IACzC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,IAAiB;QAC1B,OAAO;YACH,EAAE,EAAE,IAAI,CAAC,gBAAgB;YACzB,KAAK,EAAE,IAAI,CAAC,eAAe;SAC9B,CAAA;IACL,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,IAAiB;QAC1B,OAAO,IAAI,CAAA;IACf,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,IAAiB;QACrB,OAAO,KAAK,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,IAAiB;QACvB,OAAO,IAAI,CAAC,gBAAgB,CAAA;IAChC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,IAAiB;QAC1B,OAAO,IAAI,CAAC,eAAe,CAAA;IAC/B,CAAC;CACJ"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User information extracted from Keycloak JWT via Apache APISIX headers.
|
|
3
|
+
*
|
|
4
|
+
* This interface represents the authenticated user data parsed from APISIX
|
|
5
|
+
* headers after Keycloak authentication. APISIX forwards these headers:
|
|
6
|
+
* - `x-user-id`: The Keycloak user UUID
|
|
7
|
+
* - `x-user-roles`: Comma-separated list of user roles
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const authUser = ApisixAuthParser.parseAuthHeaders(req.headers)
|
|
12
|
+
* if (authUser) {
|
|
13
|
+
* console.log(`User ${authUser.id} has roles: ${authUser.roles.join(', ')}`)
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export interface AuthenticatedUser {
|
|
18
|
+
/** User ID from Keycloak (x-user-id header) - UUID format */
|
|
19
|
+
id: string;
|
|
20
|
+
/** User roles from Keycloak (x-user-roles header, parsed from comma-separated string) */
|
|
21
|
+
roles: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* User record stored in the database.
|
|
25
|
+
*
|
|
26
|
+
* Represents a user stored in the normalized user management system.
|
|
27
|
+
* Users are created automatically when they first access the system
|
|
28
|
+
* after being authenticated by Keycloak via APISIX.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const userService = new UserService(database)
|
|
33
|
+
* const userRecord = await userService.findOrCreateUser(authenticatedUser)
|
|
34
|
+
* console.log(`User ${userRecord.keycloak_id} has ${userRecord.roles.length} roles`)
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export interface UserRecord {
|
|
38
|
+
/** Primary key (auto-increment) */
|
|
39
|
+
id?: number;
|
|
40
|
+
/** Keycloak user ID (UUID, unique across system) */
|
|
41
|
+
keycloak_id: string;
|
|
42
|
+
/** User roles (populated from user_roles junction table) */
|
|
43
|
+
roles: string[];
|
|
44
|
+
/** First time the user was seen in the system */
|
|
45
|
+
created_at: Date;
|
|
46
|
+
/** Last time the user's roles were updated */
|
|
47
|
+
updated_at: Date;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Authentication context passed to handlers.
|
|
51
|
+
*
|
|
52
|
+
* Contains both the raw authentication data from APISIX headers
|
|
53
|
+
* and the corresponding database user record. Used internally
|
|
54
|
+
* by components that need full user context.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const authContext: AuthContext = {
|
|
59
|
+
* user: authUser,
|
|
60
|
+
* userRecord: await userService.findOrCreateUser(authUser)
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export interface AuthContext {
|
|
65
|
+
/** Authenticated user information from APISIX headers */
|
|
66
|
+
user: AuthenticatedUser;
|
|
67
|
+
/** Database user record with full role information */
|
|
68
|
+
userRecord: UserRecord;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Request object extended with authentication context.
|
|
72
|
+
*
|
|
73
|
+
* Represents an HTTP request that has been augmented with
|
|
74
|
+
* authentication information. Used by handlers that need
|
|
75
|
+
* access to both request data and user context.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* async function handleRequest(req: AuthenticatedRequest) {
|
|
80
|
+
* if (req.auth) {
|
|
81
|
+
* console.log(`Request from user: ${req.auth.user.id}`)
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export interface AuthenticatedRequest {
|
|
87
|
+
/** Original Express request object */
|
|
88
|
+
originalRequest: any;
|
|
89
|
+
/** Authentication context (undefined if not authenticated) */
|
|
90
|
+
auth?: AuthContext;
|
|
91
|
+
/** Request headers (including APISIX authentication headers) */
|
|
92
|
+
headers: Record<string, string>;
|
|
93
|
+
/** URL parameters */
|
|
94
|
+
params?: Record<string, string>;
|
|
95
|
+
/** Request body */
|
|
96
|
+
body?: any;
|
|
97
|
+
/** File upload (for multipart requests with assets) */
|
|
98
|
+
file?: any;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAC9B,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAA;IACV,yFAAyF;IACzF,KAAK,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IACvB,mCAAmC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,4DAA4D;IAC5D,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,iDAAiD;IACjD,UAAU,EAAE,IAAI,CAAA;IAChB,8CAA8C;IAC9C,UAAU,EAAE,IAAI,CAAA;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IACxB,yDAAyD;IACzD,IAAI,EAAE,iBAAiB,CAAA;IACvB,sDAAsD;IACtD,UAAU,EAAE,UAAU,CAAA;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IACjC,sCAAsC;IACtC,eAAe,EAAE,GAAG,CAAA;IACpB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,mBAAmB;IACnB,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,uDAAuD;IACvD,IAAI,CAAC,EAAE,GAAG,CAAA;CACb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from '../database/database_adapter.js';
|
|
2
|
+
import type { AuthenticatedUser, UserRecord } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Service for managing users in the Digital Twin framework.
|
|
5
|
+
*
|
|
6
|
+
* This service handles the complete user lifecycle in a Digital Twin application
|
|
7
|
+
* with Keycloak authentication via Apache APISIX. It manages a normalized database
|
|
8
|
+
* schema with three tables:
|
|
9
|
+
*
|
|
10
|
+
* - `users`: Core user records linked to Keycloak IDs
|
|
11
|
+
* - `roles`: Master list of available roles
|
|
12
|
+
* - `user_roles`: Many-to-many relationship between users and roles
|
|
13
|
+
*
|
|
14
|
+
* Key features:
|
|
15
|
+
* - Automatic user creation on first authentication
|
|
16
|
+
* - Role synchronization with Keycloak
|
|
17
|
+
* - Optimized queries with proper indexing
|
|
18
|
+
* - Transaction-safe role updates
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Initialize in your Digital Twin engine
|
|
23
|
+
* const userService = new UserService(databaseAdapter)
|
|
24
|
+
* await userService.initializeTables()
|
|
25
|
+
*
|
|
26
|
+
* // Use in AssetsManager handlers
|
|
27
|
+
* const authUser = ApisixAuthParser.parseAuthHeaders(req.headers)
|
|
28
|
+
* const userRecord = await userService.findOrCreateUser(authUser!)
|
|
29
|
+
*
|
|
30
|
+
* // Link assets to users
|
|
31
|
+
* await this.uploadAsset({
|
|
32
|
+
* description: 'My file',
|
|
33
|
+
* source: 'upload',
|
|
34
|
+
* owner_id: userRecord.id!.toString(),
|
|
35
|
+
* filename: 'document.pdf',
|
|
36
|
+
* file: buffer
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class UserService {
|
|
41
|
+
private db;
|
|
42
|
+
private readonly usersTable;
|
|
43
|
+
private readonly rolesTable;
|
|
44
|
+
private readonly userRolesTable;
|
|
45
|
+
constructor(db: DatabaseAdapter);
|
|
46
|
+
/**
|
|
47
|
+
* Ensures all user-related tables exist in the database
|
|
48
|
+
*/
|
|
49
|
+
initializeTables(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Finds or creates a user and synchronizes their roles.
|
|
52
|
+
*
|
|
53
|
+
* When authentication is disabled, returns a mock user record
|
|
54
|
+
* without touching the database.
|
|
55
|
+
*/
|
|
56
|
+
findOrCreateUser(authUser: AuthenticatedUser): Promise<UserRecord>;
|
|
57
|
+
/**
|
|
58
|
+
* Gets a user by their database ID
|
|
59
|
+
*/
|
|
60
|
+
getUserById(id: number): Promise<UserRecord | undefined>;
|
|
61
|
+
/**
|
|
62
|
+
* Gets a user by their Keycloak ID with roles
|
|
63
|
+
*/
|
|
64
|
+
getUserByKeycloakId(keycloakId: string): Promise<UserRecord | undefined>;
|
|
65
|
+
/**
|
|
66
|
+
* Gets the underlying Knex instance from the database adapter
|
|
67
|
+
*/
|
|
68
|
+
private getKnex;
|
|
69
|
+
/**
|
|
70
|
+
* Finds a user by their Keycloak ID
|
|
71
|
+
*/
|
|
72
|
+
private findUserByKeycloakId;
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new user record
|
|
75
|
+
*/
|
|
76
|
+
private createUser;
|
|
77
|
+
/**
|
|
78
|
+
* Synchronizes user roles with what's provided by Keycloak
|
|
79
|
+
*/
|
|
80
|
+
private syncUserRoles;
|
|
81
|
+
/**
|
|
82
|
+
* Gets a user with their roles populated
|
|
83
|
+
*/
|
|
84
|
+
private getUserWithRoles;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=user_service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user_service.d.ts","sourceRoot":"","sources":["../../src/auth/user_service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAI/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAe;gBAElC,EAAE,EAAE,eAAe;IAI/B;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkDvC;;;;;OAKG;IACG,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IA8BxE;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI9D;;OAEG;IACG,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAY9E;;OAEG;IACH,OAAO,CAAC,OAAO;IAOf;;OAEG;YACW,oBAAoB;IAgBlC;;OAEG;YACW,UAAU;IAuBxB;;OAEG;YACW,aAAa;IAoC3B;;OAEG;YACW,gBAAgB;CAqCjC"}
|