emilsoftware-utilities 2.0.0-dev.65 → 2.0.0-dev.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.MD +28 -1
  2. package/dist/EmilsoftwareModule.d.ts +11 -3
  3. package/dist/EmilsoftwareModule.js +1 -1
  4. package/dist/EmilsoftwareModule.js.map +1 -1
  5. package/dist/Orm.d.ts +1 -1
  6. package/dist/Orm.js +4 -23
  7. package/dist/Orm.js.map +1 -1
  8. package/dist/Utilities.js +1 -0
  9. package/dist/Utilities.js.map +1 -1
  10. package/dist/accessi/client/index.d.ts +26 -0
  11. package/dist/accessi/client/index.js +49 -0
  12. package/dist/accessi/client/index.js.map +1 -0
  13. package/dist/accessi/console/index.d.ts +15 -0
  14. package/dist/accessi/console/index.js +25 -0
  15. package/dist/accessi/console/index.js.map +1 -0
  16. package/dist/accessi/contracts/dtos.d.ts +8 -0
  17. package/dist/accessi/contracts/dtos.js +25 -0
  18. package/dist/accessi/contracts/dtos.js.map +1 -0
  19. package/dist/accessi/contracts/index.d.ts +25 -0
  20. package/dist/accessi/contracts/index.js +28 -0
  21. package/dist/accessi/contracts/index.js.map +1 -0
  22. package/dist/accessi/openapi/index.d.ts +2 -0
  23. package/dist/accessi/openapi/index.js +19 -0
  24. package/dist/accessi/openapi/index.js.map +1 -0
  25. package/dist/accessi/resource-server/core.d.ts +6 -0
  26. package/dist/accessi/resource-server/core.js +23 -0
  27. package/dist/accessi/resource-server/core.js.map +1 -0
  28. package/dist/accessi/resource-server/errors.d.ts +10 -0
  29. package/dist/accessi/resource-server/errors.js +19 -0
  30. package/dist/accessi/resource-server/errors.js.map +1 -0
  31. package/dist/accessi/resource-server/express.d.ts +17 -0
  32. package/dist/accessi/resource-server/express.js +66 -0
  33. package/dist/accessi/resource-server/express.js.map +1 -0
  34. package/dist/accessi/resource-server/index.d.ts +3 -0
  35. package/dist/accessi/resource-server/index.js +20 -0
  36. package/dist/accessi/resource-server/index.js.map +1 -0
  37. package/dist/accessi/resource-server/introspection.d.ts +16 -0
  38. package/dist/accessi/resource-server/introspection.js +115 -0
  39. package/dist/accessi/resource-server/introspection.js.map +1 -0
  40. package/dist/accessi/resource-server/keys.d.ts +11 -0
  41. package/dist/accessi/resource-server/keys.js +22 -0
  42. package/dist/accessi/resource-server/keys.js.map +1 -0
  43. package/dist/accessi/resource-server/nest.d.ts +9 -0
  44. package/dist/accessi/resource-server/nest.js +62 -0
  45. package/dist/accessi/resource-server/nest.js.map +1 -0
  46. package/dist/accessi/resource-server/runtime.d.ts +27 -0
  47. package/dist/accessi/resource-server/runtime.js +128 -0
  48. package/dist/accessi/resource-server/runtime.js.map +1 -0
  49. package/dist/accessi/resource-server/token.d.ts +23 -0
  50. package/dist/accessi/resource-server/token.js +230 -0
  51. package/dist/accessi/resource-server/token.js.map +1 -0
  52. package/dist/accessi/resource-server/types.d.ts +78 -0
  53. package/dist/accessi/resource-server/types.js +3 -0
  54. package/dist/accessi/resource-server/types.js.map +1 -0
  55. package/dist/accessi/server/index.d.ts +10 -0
  56. package/dist/accessi/server/index.js +29 -0
  57. package/dist/accessi/server/index.js.map +1 -0
  58. package/dist/accessi/ui/index.d.ts +13 -0
  59. package/dist/accessi/ui/index.js +19 -0
  60. package/dist/accessi/ui/index.js.map +1 -0
  61. package/dist/accessi-module/AccessiModule.d.ts +25 -1
  62. package/dist/accessi-module/AccessiModule.js +2 -0
  63. package/dist/accessi-module/AccessiModule.js.map +1 -1
  64. package/dist/accessi-module/Console/accessiFetch.d.ts +4 -0
  65. package/dist/accessi-module/Console/accessiFetch.js +18 -4
  66. package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
  67. package/dist/accessi-module/Console/console.js +114 -9
  68. package/dist/accessi-module/Console/console.js.map +1 -1
  69. package/dist/accessi-module/Console/generated/{accessiApi.d.ts → emilsoftware-utilities.d.ts} +11 -1
  70. package/dist/accessi-module/Console/generated/{accessiApi.js → emilsoftware-utilities.js} +10 -2
  71. package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -0
  72. package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.d.ts +16 -0
  73. package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.js +3 -0
  74. package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.js.map +1 -0
  75. package/dist/accessi-module/Console/generated/model/index.d.ts +3 -0
  76. package/dist/accessi-module/Console/generated/model/index.js +3 -0
  77. package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
  78. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.d.ts +10 -0
  79. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.js +9 -0
  80. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.js.map +1 -0
  81. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.d.ts +14 -0
  82. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.js +3 -0
  83. package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.js.map +1 -0
  84. package/dist/accessi-module/Console/wiki.js +98 -3
  85. package/dist/accessi-module/Console/wiki.js.map +1 -1
  86. package/dist/accessi-module/Controllers/AccessiIntrospectionController.d.ts +17 -0
  87. package/dist/accessi-module/Controllers/AccessiIntrospectionController.js +93 -0
  88. package/dist/accessi-module/Controllers/AccessiIntrospectionController.js.map +1 -0
  89. package/dist/accessi-module/Dtos/IntrospectionDtos.d.ts +16 -0
  90. package/dist/accessi-module/Dtos/IntrospectionDtos.js +59 -0
  91. package/dist/accessi-module/Dtos/IntrospectionDtos.js.map +1 -0
  92. package/dist/accessi-module/Dtos/index.d.ts +1 -0
  93. package/dist/accessi-module/Dtos/index.js +1 -0
  94. package/dist/accessi-module/Dtos/index.js.map +1 -1
  95. package/dist/accessi-module/Services/AuthService/AuthService.d.ts +13 -0
  96. package/dist/accessi-module/Services/AuthService/AuthService.js +42 -10
  97. package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
  98. package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js +11 -4
  99. package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js.map +1 -1
  100. package/dist/accessi-module/database-updates/menuScopeSeed.d.ts +2 -2
  101. package/dist/accessi-module/database-updates/menuScopeSeed.js +101 -53
  102. package/dist/accessi-module/database-updates/menuScopeSeed.js.map +1 -1
  103. package/dist/accessi-module/database-updates/menuScopeSeeder.js +1 -1
  104. package/dist/accessi-module/database-updates/menuScopeSeeder.js.map +1 -1
  105. package/dist/accessi-module/index.d.ts +16 -3
  106. package/dist/accessi-module/index.js +15 -19
  107. package/dist/accessi-module/index.js.map +1 -1
  108. package/dist/accessi-module/jwt/jwt.strategy.js +5 -5
  109. package/dist/accessi-module/jwt/jwt.strategy.js.map +1 -1
  110. package/dist/accessi-module/middleware/authenticateGen.js +5 -5
  111. package/dist/accessi-module/middleware/authenticateGen.js.map +1 -1
  112. package/dist/accessi-module/security/jwtTokenOptions.d.ts +15 -0
  113. package/dist/accessi-module/security/jwtTokenOptions.js +44 -0
  114. package/dist/accessi-module/security/jwtTokenOptions.js.map +1 -0
  115. package/dist/accessi-module/startupLog.d.ts +3 -2
  116. package/dist/accessi-module/startupLog.js +8 -4
  117. package/dist/accessi-module/startupLog.js.map +1 -1
  118. package/dist/allegati-module/index.js +2 -2
  119. package/dist/allegati-module/index.js.map +1 -1
  120. package/dist/angular-components/aree-disponibili/demo.html +4 -4
  121. package/dist/emilsoftware-utilities-2.0.0-dev.67.tgz +0 -0
  122. package/dist/firebird-compat.d.ts +27 -0
  123. package/dist/firebird-compat.js +52 -2
  124. package/dist/firebird-compat.js.map +1 -1
  125. package/dist/index.d.ts +2 -1
  126. package/dist/index.js +2 -1
  127. package/dist/index.js.map +1 -1
  128. package/dist/initEmilsoftwareModule.d.ts +11 -1
  129. package/dist/initEmilsoftwareModule.js +11 -23
  130. package/dist/initEmilsoftwareModule.js.map +1 -1
  131. package/dist/openapi/OpenApiConfig.d.ts +68 -0
  132. package/dist/openapi/OpenApiConfig.js +157 -0
  133. package/dist/openapi/OpenApiConfig.js.map +1 -0
  134. package/dist/openapi/OpenApiMerge.d.ts +15 -0
  135. package/dist/openapi/OpenApiMerge.js +119 -0
  136. package/dist/openapi/OpenApiMerge.js.map +1 -0
  137. package/integration-prompt.md +481 -0
  138. package/package.json +89 -6
  139. package/dist/accessi-module/Console/generated/accessiApi.js.map +0 -1
  140. package/dist/emilsoftware-utilities-2.0.0-dev.65.tgz +0 -0
  141. package/dist/swagger/SwaggerConfig.d.ts +0 -8
  142. package/dist/swagger/SwaggerConfig.js +0 -41
  143. package/dist/swagger/SwaggerConfig.js.map +0 -1
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.createAccessiAuthGuard = createAccessiAuthGuard;
19
+ const common_1 = require("@nestjs/common");
20
+ const errors_1 = require("./errors");
21
+ const runtime_1 = require("./runtime");
22
+ function toNestException(error) {
23
+ const normalized = error instanceof errors_1.AccessiResourceServerError
24
+ ? error
25
+ : new errors_1.AccessiResourceServerError(500, "AUTH_INTERNAL_ERROR", "Errore interno durante l'autenticazione.");
26
+ const payload = { code: normalized.code, message: normalized.message };
27
+ if (normalized.status === 401)
28
+ return new common_1.UnauthorizedException(payload);
29
+ if (normalized.status === 403)
30
+ return new common_1.ForbiddenException(payload);
31
+ if (normalized.status === 503)
32
+ return new common_1.ServiceUnavailableException(payload);
33
+ return new common_1.InternalServerErrorException(payload);
34
+ }
35
+ /**
36
+ * Crea un guard Nest configurato con le opzioni del resource server.
37
+ *
38
+ * Uso:
39
+ * `@UseGuards(createAccessiAuthGuard(options))`
40
+ */
41
+ function createAccessiAuthGuard(options) {
42
+ const runtime = (0, runtime_1.createAccessiResourceServer)(options);
43
+ let ConfiguredAccessiAuthGuard = class ConfiguredAccessiAuthGuard {
44
+ canActivate(context) {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ const request = context.switchToHttp().getRequest();
47
+ try {
48
+ yield (0, runtime_1.authenticateAccessiRequest)(request, runtime);
49
+ return true;
50
+ }
51
+ catch (error) {
52
+ throw toNestException(error);
53
+ }
54
+ });
55
+ }
56
+ };
57
+ ConfiguredAccessiAuthGuard = __decorate([
58
+ (0, common_1.Injectable)()
59
+ ], ConfiguredAccessiAuthGuard);
60
+ return ConfiguredAccessiAuthGuard;
61
+ }
62
+ //# sourceMappingURL=nest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nest.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/nest.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAiCA,wDAmBC;AApDD,2CASwB;AAExB,qCAAsD;AACtD,uCAAoF;AAGpF,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,UAAU,GAAG,KAAK,YAAY,mCAA0B;QAC5D,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,mCAA0B,CAAC,GAAG,EAAE,qBAAqB,EAAE,0CAA0C,CAAC,CAAC;IAC3G,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC;IAEvE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,8BAAqB,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,2BAAkB,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,oCAA2B,CAAC,OAAO,CAAC,CAAC;IAC/E,OAAO,IAAI,qCAA4B,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CACpC,OAAqC;IAErC,MAAM,OAAO,GAAG,IAAA,qCAA2B,EAAC,OAAO,CAAC,CAAC;IAGrD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;QACxB,WAAW,CAAC,OAAyB;;gBACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;gBAC7D,IAAI,CAAC;oBACH,MAAM,IAAA,oCAA0B,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;SAAA;KACF,CAAA;IAVK,0BAA0B;QAD/B,IAAA,mBAAU,GAAE;OACP,0BAA0B,CAU/B;IAED,OAAO,0BAA0B,CAAC;AACpC,CAAC","sourcesContent":["import {\n CanActivate,\n ExecutionContext,\n ForbiddenException,\n Injectable,\n InternalServerErrorException,\n ServiceUnavailableException,\n Type,\n UnauthorizedException,\n} from \"@nestjs/common\";\nimport type { Request } from \"express\";\nimport { AccessiResourceServerError } from \"./errors\";\nimport { authenticateAccessiRequest, createAccessiResourceServer } from \"./runtime\";\nimport type { AccessiResourceServerOptions } from \"./types\";\n\nfunction toNestException(error: unknown): Error {\n const normalized = error instanceof AccessiResourceServerError\n ? error\n : new AccessiResourceServerError(500, \"AUTH_INTERNAL_ERROR\", \"Errore interno durante l'autenticazione.\");\n const payload = { code: normalized.code, message: normalized.message };\n\n if (normalized.status === 401) return new UnauthorizedException(payload);\n if (normalized.status === 403) return new ForbiddenException(payload);\n if (normalized.status === 503) return new ServiceUnavailableException(payload);\n return new InternalServerErrorException(payload);\n}\n\n/**\n * Crea un guard Nest configurato con le opzioni del resource server.\n *\n * Uso:\n * `@UseGuards(createAccessiAuthGuard(options))`\n */\nexport function createAccessiAuthGuard(\n options: AccessiResourceServerOptions,\n): Type<CanActivate> {\n const runtime = createAccessiResourceServer(options);\n\n @Injectable()\n class ConfiguredAccessiAuthGuard implements CanActivate {\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<Request>();\n try {\n await authenticateAccessiRequest(request, runtime);\n return true;\n } catch (error) {\n throw toNestException(error);\n }\n }\n }\n\n return ConfiguredAccessiAuthGuard;\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import type { Request } from "express";
2
+ import type { GrantsResult } from "../contracts";
3
+ import type { AccessiIntrospectionClient } from "./introspection";
4
+ import type { AccessiTokenVerifier } from "./token";
5
+ import type { AccessiRequestContext, AccessiResourceServerOptions } from "./types";
6
+ /** Request Express arricchita dal resource server. */
7
+ export interface AccessiAuthenticatedRequest extends Request {
8
+ user?: Record<string, unknown>;
9
+ data?: Record<string, unknown>;
10
+ userGrants?: GrantsResult;
11
+ accessi?: AccessiRequestContext;
12
+ }
13
+ /** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */
14
+ export interface AccessiResourceServerRuntime {
15
+ options: AccessiResourceServerOptions;
16
+ verifier?: AccessiTokenVerifier;
17
+ introspectionClient?: AccessiIntrospectionClient;
18
+ }
19
+ /** Valida la configurazione e prepara verificatore e client di introspection. */
20
+ export declare function createAccessiResourceServer(options: AccessiResourceServerOptions): AccessiResourceServerRuntime;
21
+ /**
22
+ * Autentica la request e applica l'eventuale policy di autorizzazione.
23
+ *
24
+ * Non accede mai al database Accessi: la verifica e locale oppure delegata
25
+ * all'introspection di Accessi Service.
26
+ */
27
+ export declare function authenticateAccessiRequest(request: Request, runtime: AccessiResourceServerRuntime): Promise<AccessiRequestContext>;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createAccessiResourceServer = createAccessiResourceServer;
13
+ exports.authenticateAccessiRequest = authenticateAccessiRequest;
14
+ const contracts_1 = require("../contracts");
15
+ const errors_1 = require("./errors");
16
+ const introspection_1 = require("./introspection");
17
+ const token_1 = require("./token");
18
+ function resolveMode(options) {
19
+ if (options.mode)
20
+ return options.mode;
21
+ if (options.jwt)
22
+ return "local";
23
+ if (options.introspection)
24
+ return "introspection";
25
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Configurare jwt o introspection nel resource server Accessi.");
26
+ }
27
+ /** Valida la configurazione e prepara verificatore e client di introspection. */
28
+ function createAccessiResourceServer(options) {
29
+ const mode = resolveMode(options);
30
+ if (mode === "local" && !options.jwt) {
31
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "mode local richiede jwt.");
32
+ }
33
+ if (mode === "introspection" && !options.introspection) {
34
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "mode introspection richiede introspection.");
35
+ }
36
+ return Object.assign(Object.assign({ options: Object.assign(Object.assign({}, options), { mode }) }, (options.jwt ? { verifier: (0, token_1.createAccessiTokenVerifier)(options.jwt) } : {})), (options.introspection
37
+ ? { introspectionClient: (0, introspection_1.createAccessiIntrospectionClient)(options.introspection) }
38
+ : {}));
39
+ }
40
+ function mergeIntrospectionUser(payload, user) {
41
+ return Object.assign(Object.assign(Object.assign({}, (payload !== null && payload !== void 0 ? payload : { typ: "access" })), user), { typ: "access", utente: user });
42
+ }
43
+ /**
44
+ * Autentica la request e applica l'eventuale policy di autorizzazione.
45
+ *
46
+ * Non accede mai al database Accessi: la verifica e locale oppure delegata
47
+ * all'introspection di Accessi Service.
48
+ */
49
+ function authenticateAccessiRequest(request, runtime) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ var _a, _b;
52
+ const token = (0, contracts_1.extractAccessiBearerToken)(request.headers.authorization);
53
+ if (!token) {
54
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_MISSING", "Token Bearer mancante o malformato.");
55
+ }
56
+ const mode = (_a = runtime.options.mode) !== null && _a !== void 0 ? _a : "local";
57
+ let payload;
58
+ let user = {};
59
+ let codiceUtente;
60
+ let grants;
61
+ if (mode === "local") {
62
+ if (!runtime.verifier) {
63
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Verificatore JWT non configurato.");
64
+ }
65
+ const verification = yield runtime.verifier.verify(token);
66
+ payload = verification.payload;
67
+ user = verification.user;
68
+ codiceUtente = verification.codiceUtente;
69
+ }
70
+ else {
71
+ if (!runtime.introspectionClient) {
72
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Client introspection non configurato.");
73
+ }
74
+ const introspection = yield runtime.introspectionClient.introspect(token);
75
+ if (!introspection.active) {
76
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token non valido, scaduto o revocato.");
77
+ }
78
+ user = (_b = introspection.user) !== null && _b !== void 0 ? _b : {};
79
+ codiceUtente = introspection.codiceUtente;
80
+ grants = introspection.grants;
81
+ payload = mergeIntrospectionUser(undefined, user);
82
+ }
83
+ if (!codiceUtente) {
84
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_USER_CODE_MISSING", "Token privo di un utente valido.");
85
+ }
86
+ const requirementTree = (0, contracts_1.buildRequirementTree)(runtime.options.authorization);
87
+ if (requirementTree) {
88
+ if (!grants) {
89
+ if (!runtime.introspectionClient) {
90
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_GRANTS_SOURCE_MISSING", "La policy richiede grant ma introspection non e configurata.");
91
+ }
92
+ const introspection = yield runtime.introspectionClient.introspect(token);
93
+ if (!introspection.active) {
94
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token non valido, scaduto o revocato.");
95
+ }
96
+ grants = introspection.grants;
97
+ if (introspection.user) {
98
+ user = introspection.user;
99
+ payload = mergeIntrospectionUser(payload, user);
100
+ }
101
+ }
102
+ const hasPermissions = yield (0, contracts_1.evaluateRequirement)(requirementTree, {
103
+ req: request,
104
+ decodedToken: payload,
105
+ userCode: codiceUtente,
106
+ getGrantsResult: () => __awaiter(this, void 0, void 0, function* () { return grants !== null && grants !== void 0 ? grants : {}; }),
107
+ }, runtime.options.authorization);
108
+ if (!hasPermissions) {
109
+ throw (0, errors_1.accessiAuthError)(403, "AUTH_INSUFFICIENT_PERMISSIONS", "Permessi insufficienti per questa operazione.");
110
+ }
111
+ }
112
+ const authenticatedRequest = request;
113
+ const authPayload = payload !== null && payload !== void 0 ? payload : {
114
+ typ: "access",
115
+ codiceUtente,
116
+ utente: user,
117
+ };
118
+ authenticatedRequest.user = authPayload;
119
+ authenticatedRequest.data = authPayload;
120
+ if (grants)
121
+ authenticatedRequest.userGrants = grants;
122
+ authenticatedRequest.accessi = Object.assign(Object.assign({ token,
123
+ user,
124
+ codiceUtente }, (grants ? { grants } : {})), { payload: authPayload });
125
+ return authenticatedRequest.accessi;
126
+ });
127
+ }
128
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Request } from \"express\";\nimport {\n buildRequirementTree,\n evaluateRequirement,\n extractAccessiBearerToken,\n} from \"../contracts\";\nimport type {\n AccessiAccessTokenPayload,\n GrantsResult,\n} from \"../contracts\";\nimport { accessiAuthError } from \"./errors\";\nimport { createAccessiIntrospectionClient } from \"./introspection\";\nimport type { AccessiIntrospectionClient } from \"./introspection\";\nimport { createAccessiTokenVerifier } from \"./token\";\nimport type { AccessiTokenVerifier } from \"./token\";\nimport type {\n AccessiRequestContext,\n AccessiResourceServerOptions,\n} from \"./types\";\n\n/** Request Express arricchita dal resource server. */\nexport interface AccessiAuthenticatedRequest extends Request {\n user?: Record<string, unknown>;\n data?: Record<string, unknown>;\n userGrants?: GrantsResult;\n accessi?: AccessiRequestContext;\n}\n\n/** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */\nexport interface AccessiResourceServerRuntime {\n options: AccessiResourceServerOptions;\n verifier?: AccessiTokenVerifier;\n introspectionClient?: AccessiIntrospectionClient;\n}\n\nfunction resolveMode(options: AccessiResourceServerOptions): \"local\" | \"introspection\" {\n if (options.mode) return options.mode;\n if (options.jwt) return \"local\";\n if (options.introspection) return \"introspection\";\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"Configurare jwt o introspection nel resource server Accessi.\",\n );\n}\n\n/** Valida la configurazione e prepara verificatore e client di introspection. */\nexport function createAccessiResourceServer(\n options: AccessiResourceServerOptions,\n): AccessiResourceServerRuntime {\n const mode = resolveMode(options);\n if (mode === \"local\" && !options.jwt) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode local richiede jwt.\");\n }\n if (mode === \"introspection\" && !options.introspection) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode introspection richiede introspection.\");\n }\n\n return {\n options: { ...options, mode },\n ...(options.jwt ? { verifier: createAccessiTokenVerifier(options.jwt) } : {}),\n ...(options.introspection\n ? { introspectionClient: createAccessiIntrospectionClient(options.introspection) }\n : {}),\n };\n}\n\nfunction mergeIntrospectionUser(\n payload: AccessiAccessTokenPayload | undefined,\n user: Record<string, unknown>,\n): AccessiAccessTokenPayload {\n return {\n ...(payload ?? { typ: \"access\" }),\n ...user,\n typ: \"access\",\n utente: user,\n };\n}\n\n/**\n * Autentica la request e applica l'eventuale policy di autorizzazione.\n *\n * Non accede mai al database Accessi: la verifica e locale oppure delegata\n * all'introspection di Accessi Service.\n */\nexport async function authenticateAccessiRequest(\n request: Request,\n runtime: AccessiResourceServerRuntime,\n): Promise<AccessiRequestContext> {\n const token = extractAccessiBearerToken(request.headers.authorization);\n if (!token) {\n throw accessiAuthError(401, \"AUTH_TOKEN_MISSING\", \"Token Bearer mancante o malformato.\");\n }\n\n const mode = runtime.options.mode ?? \"local\";\n let payload: AccessiAccessTokenPayload | undefined;\n let user: Record<string, unknown> = {};\n let codiceUtente: number | undefined;\n let grants: GrantsResult | undefined;\n\n if (mode === \"local\") {\n if (!runtime.verifier) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Verificatore JWT non configurato.\");\n }\n const verification = await runtime.verifier.verify(token);\n payload = verification.payload;\n user = verification.user;\n codiceUtente = verification.codiceUtente;\n } else {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Client introspection non configurato.\");\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n user = introspection.user ?? {};\n codiceUtente = introspection.codiceUtente;\n grants = introspection.grants;\n payload = mergeIntrospectionUser(undefined, user);\n }\n\n if (!codiceUtente) {\n throw accessiAuthError(401, \"AUTH_USER_CODE_MISSING\", \"Token privo di un utente valido.\");\n }\n\n const requirementTree = buildRequirementTree(runtime.options.authorization);\n if (requirementTree) {\n if (!grants) {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(\n 500,\n \"AUTH_GRANTS_SOURCE_MISSING\",\n \"La policy richiede grant ma introspection non e configurata.\",\n );\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n grants = introspection.grants;\n if (introspection.user) {\n user = introspection.user;\n payload = mergeIntrospectionUser(payload, user);\n }\n }\n\n const hasPermissions = await evaluateRequirement(\n requirementTree,\n {\n req: request,\n decodedToken: payload,\n userCode: codiceUtente,\n getGrantsResult: async () => grants ?? {},\n },\n runtime.options.authorization,\n );\n if (!hasPermissions) {\n throw accessiAuthError(\n 403,\n \"AUTH_INSUFFICIENT_PERMISSIONS\",\n \"Permessi insufficienti per questa operazione.\",\n );\n }\n }\n\n const authenticatedRequest = request as AccessiAuthenticatedRequest;\n const authPayload: Record<string, unknown> = payload ?? {\n typ: \"access\",\n codiceUtente,\n utente: user,\n };\n authenticatedRequest.user = authPayload;\n authenticatedRequest.data = authPayload;\n if (grants) authenticatedRequest.userGrants = grants;\n authenticatedRequest.accessi = {\n token,\n user,\n codiceUtente,\n ...(grants ? { grants } : {}),\n payload: authPayload,\n };\n return authenticatedRequest.accessi;\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { AccessiAccessTokenPayload } from "../contracts";
2
+ import type { AccessiResourceServerJwtOptions } from "./types";
3
+ /** Esito della verifica locale di un access token. */
4
+ export interface AccessiTokenVerification {
5
+ token: string;
6
+ payload: AccessiAccessTokenPayload;
7
+ codiceUtente: number;
8
+ user: Record<string, unknown>;
9
+ }
10
+ /** Verificatore riutilizzabile: conserva la cache JWKS tra una richiesta e l'altra. */
11
+ export interface AccessiTokenVerifier {
12
+ verify(token: string): Promise<AccessiTokenVerification>;
13
+ verifyAuthorizationHeader(header: unknown): Promise<AccessiTokenVerification>;
14
+ }
15
+ /**
16
+ * Crea un verificatore locale riutilizzabile.
17
+ *
18
+ * Supporta HMAC, chiavi pubbliche PEM (RS ed ES) e JWKS remoto. La cache
19
+ * JWKS e legata all'istanza del verificatore.
20
+ */
21
+ export declare function createAccessiTokenVerifier(options: AccessiResourceServerJwtOptions): AccessiTokenVerifier;
22
+ /** Converte un header `Authorization` in verifica del token, senza cache JWKS condivisa. */
23
+ export declare function verifyAccessiAccessToken(header: unknown, options: AccessiResourceServerJwtOptions): Promise<AccessiTokenVerification>;
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.createAccessiTokenVerifier = createAccessiTokenVerifier;
46
+ exports.verifyAccessiAccessToken = verifyAccessiAccessToken;
47
+ const crypto_1 = require("crypto");
48
+ const jwt = __importStar(require("jsonwebtoken"));
49
+ const contracts_1 = require("../contracts");
50
+ const errors_1 = require("./errors");
51
+ const keys_1 = require("./keys");
52
+ function isRecord(value) {
53
+ return typeof value === "object" && value !== null;
54
+ }
55
+ function extractUser(payload) {
56
+ const userData = isRecord(payload.userData) ? payload.userData : undefined;
57
+ const utente = isRecord(payload.utente)
58
+ ? payload.utente
59
+ : isRecord(userData === null || userData === void 0 ? void 0 : userData.utente)
60
+ ? userData.utente
61
+ : undefined;
62
+ return utente !== null && utente !== void 0 ? utente : {};
63
+ }
64
+ function defaultAlgorithms(options) {
65
+ if (options.algorithms && options.algorithms.length > 0)
66
+ return options.algorithms;
67
+ const algorithms = [];
68
+ if (options.secret || options.serverSecret)
69
+ algorithms.push("HS256");
70
+ if (options.publicKey || options.jwks) {
71
+ algorithms.push("RS256", "RS384", "RS512", "ES256", "ES384", "ES512");
72
+ }
73
+ return algorithms;
74
+ }
75
+ function algorithmFamily(algorithm) {
76
+ return algorithm.startsWith("HS") ? "hmac" : "asymmetric";
77
+ }
78
+ function fetchJwks(options) {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ var _a, _b;
81
+ const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch;
82
+ if (typeof fetchImpl !== "function") {
83
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "fetch non disponibile per caricare la JWKS.");
84
+ }
85
+ const controller = new AbortController();
86
+ const timeout = setTimeout(() => controller.abort(), (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : 3000);
87
+ try {
88
+ const response = yield fetchImpl(options.url, {
89
+ method: "GET",
90
+ headers: { Accept: "application/json" },
91
+ signal: controller.signal,
92
+ });
93
+ if (!response.ok) {
94
+ throw (0, errors_1.accessiAuthError)(503, "AUTH_JWKS_UNAVAILABLE", `JWKS non disponibile (HTTP ${response.status}).`);
95
+ }
96
+ const payload = yield response.json();
97
+ if (!isRecord(payload) || !Array.isArray(payload.keys)) {
98
+ throw (0, errors_1.accessiAuthError)(503, "AUTH_JWKS_UNAVAILABLE", "Risposta JWKS non valida.");
99
+ }
100
+ return payload.keys.filter(isRecord);
101
+ }
102
+ catch (error) {
103
+ if (error && typeof error === "object" && "code" in error && "status" in error) {
104
+ throw error;
105
+ }
106
+ throw (0, errors_1.accessiAuthError)(503, "AUTH_JWKS_UNAVAILABLE", "JWKS non raggiungibile.");
107
+ }
108
+ finally {
109
+ clearTimeout(timeout);
110
+ }
111
+ });
112
+ }
113
+ function selectJwk(keys, kid, algorithm) {
114
+ const candidates = keys.filter((key) => {
115
+ const keyAlg = typeof key.alg === "string" ? key.alg : undefined;
116
+ const keyKid = typeof key.kid === "string" ? key.kid : undefined;
117
+ if (keyAlg && keyAlg !== algorithm)
118
+ return false;
119
+ if (kid && keyKid && keyKid !== kid)
120
+ return false;
121
+ return true;
122
+ });
123
+ const selected = candidates[0];
124
+ if (!selected) {
125
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Chiave JWKS non trovata per il token.");
126
+ }
127
+ return selected;
128
+ }
129
+ /**
130
+ * Crea un verificatore locale riutilizzabile.
131
+ *
132
+ * Supporta HMAC, chiavi pubbliche PEM (RS ed ES) e JWKS remoto. La cache
133
+ * JWKS e legata all'istanza del verificatore.
134
+ */
135
+ function createAccessiTokenVerifier(options) {
136
+ var _a, _b;
137
+ const algorithms = defaultAlgorithms(options);
138
+ if (algorithms.length === 0) {
139
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Configurare almeno una tra jwt.secret, jwt.serverSecret, jwt.publicKey e jwt.jwks.");
140
+ }
141
+ const clockTolerance = (_a = options.clockToleranceSeconds) !== null && _a !== void 0 ? _a : 5;
142
+ const hmacSecret = (_b = options.secret) !== null && _b !== void 0 ? _b : (options.serverSecret ? (0, keys_1.deriveAccessiAccessSecret)(options.serverSecret) : undefined);
143
+ let jwksCache;
144
+ const getJwksKeys = () => __awaiter(this, void 0, void 0, function* () {
145
+ var _a;
146
+ if (!options.jwks)
147
+ return [];
148
+ if (jwksCache && jwksCache.expiresAt > Date.now())
149
+ return jwksCache.keys;
150
+ const keys = yield fetchJwks(options.jwks);
151
+ jwksCache = {
152
+ keys,
153
+ expiresAt: Date.now() + Math.max(1000, (_a = options.jwks.cacheTtlMs) !== null && _a !== void 0 ? _a : 300000),
154
+ };
155
+ return keys;
156
+ });
157
+ const verify = (token) => __awaiter(this, void 0, void 0, function* () {
158
+ const decoded = jwt.decode(token, { complete: true });
159
+ if (!decoded || typeof decoded === "string" || !isRecord(decoded.header)) {
160
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token JWT non valido.");
161
+ }
162
+ const algorithm = typeof decoded.header.alg === "string" ? decoded.header.alg : undefined;
163
+ if (!algorithm || !algorithms.includes(algorithm)) {
164
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Algoritmo JWT non consentito.");
165
+ }
166
+ let key;
167
+ if (algorithmFamily(algorithm) === "hmac") {
168
+ if (!hmacSecret) {
169
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "jwt.secret o jwt.serverSecret non configurato per token HS*.");
170
+ }
171
+ key = hmacSecret;
172
+ }
173
+ else if (options.publicKey) {
174
+ key = options.publicKey;
175
+ }
176
+ else if (options.jwks) {
177
+ const keys = yield getJwksKeys();
178
+ const kid = typeof decoded.header.kid === "string" ? decoded.header.kid : undefined;
179
+ key = (0, crypto_1.createPublicKey)({ key: selectJwk(keys, kid, algorithm), format: "jwk" })
180
+ .export({ type: "spki", format: "pem" });
181
+ }
182
+ else {
183
+ throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "jwt.publicKey/jwt.jwks non configurati.");
184
+ }
185
+ let verified;
186
+ try {
187
+ verified = jwt.verify(token, key, Object.assign(Object.assign(Object.assign({ algorithms: [algorithm] }, (options.issuer ? { issuer: options.issuer } : {})), (options.audience
188
+ ? { audience: options.audience }
189
+ : {})), { clockTolerance }));
190
+ }
191
+ catch (_a) {
192
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token non valido o scaduto.");
193
+ }
194
+ if (!isRecord(verified)) {
195
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Payload JWT non valido.");
196
+ }
197
+ if (verified.typ !== "access") {
198
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Il token non e un access token Accessi.");
199
+ }
200
+ const codiceUtente = (0, contracts_1.resolveCodiceUtenteFromTokenPayload)(verified);
201
+ if (!codiceUtente) {
202
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_USER_CODE_MISSING", "Token privo di un utente valido.");
203
+ }
204
+ return {
205
+ token,
206
+ payload: verified,
207
+ codiceUtente,
208
+ user: extractUser(verified),
209
+ };
210
+ });
211
+ return {
212
+ verify,
213
+ verifyAuthorizationHeader(header) {
214
+ return __awaiter(this, void 0, void 0, function* () {
215
+ const token = (0, contracts_1.extractAccessiBearerToken)(header);
216
+ if (!token) {
217
+ throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_MISSING", "Token Bearer mancante o malformato.");
218
+ }
219
+ return verify(token);
220
+ });
221
+ },
222
+ };
223
+ }
224
+ /** Converte un header `Authorization` in verifica del token, senza cache JWKS condivisa. */
225
+ function verifyAccessiAccessToken(header, options) {
226
+ return __awaiter(this, void 0, void 0, function* () {
227
+ return createAccessiTokenVerifier(options).verifyAuthorizationHeader(header);
228
+ });
229
+ }
230
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/token.ts"],"names":[],"mappings":"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","sourcesContent":["import { createPublicKey } from \"crypto\";\nimport type { JsonWebKey } from \"crypto\";\nimport * as jwt from \"jsonwebtoken\";\nimport type { AccessiAccessTokenPayload } from \"../contracts\";\nimport { extractAccessiBearerToken, resolveCodiceUtenteFromTokenPayload } from \"../contracts\";\nimport { accessiAuthError } from \"./errors\";\nimport { deriveAccessiAccessSecret } from \"./keys\";\nimport type { AccessiJwtAlgorithm, AccessiResourceServerJwtOptions } from \"./types\";\n\n/** Esito della verifica locale di un access token. */\nexport interface AccessiTokenVerification {\n token: string;\n payload: AccessiAccessTokenPayload;\n codiceUtente: number;\n user: Record<string, unknown>;\n}\n\n/** Verificatore riutilizzabile: conserva la cache JWKS tra una richiesta e l'altra. */\nexport interface AccessiTokenVerifier {\n verify(token: string): Promise<AccessiTokenVerification>;\n verifyAuthorizationHeader(header: unknown): Promise<AccessiTokenVerification>;\n}\n\ninterface JwksCacheEntry {\n keys: Array<Record<string, unknown>>;\n expiresAt: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction extractUser(payload: Record<string, unknown>): Record<string, unknown> {\n const userData = isRecord(payload.userData) ? payload.userData : undefined;\n const utente = isRecord(payload.utente)\n ? payload.utente\n : isRecord(userData?.utente)\n ? userData.utente\n : undefined;\n return utente ?? {};\n}\n\nfunction defaultAlgorithms(options: AccessiResourceServerJwtOptions): AccessiJwtAlgorithm[] {\n if (options.algorithms && options.algorithms.length > 0) return options.algorithms;\n\n const algorithms: AccessiJwtAlgorithm[] = [];\n if (options.secret || options.serverSecret) algorithms.push(\"HS256\");\n if (options.publicKey || options.jwks) {\n algorithms.push(\"RS256\", \"RS384\", \"RS512\", \"ES256\", \"ES384\", \"ES512\");\n }\n return algorithms;\n}\n\nfunction algorithmFamily(algorithm: string): \"hmac\" | \"asymmetric\" {\n return algorithm.startsWith(\"HS\") ? \"hmac\" : \"asymmetric\";\n}\n\nasync function fetchJwks(\n options: NonNullable<AccessiResourceServerJwtOptions[\"jwks\"]>,\n): Promise<Array<Record<string, unknown>>> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"fetch non disponibile per caricare la JWKS.\");\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 3000);\n try {\n const response = await fetchImpl(options.url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n if (!response.ok) {\n throw accessiAuthError(\n 503,\n \"AUTH_JWKS_UNAVAILABLE\",\n `JWKS non disponibile (HTTP ${response.status}).`,\n );\n }\n const payload: unknown = await response.json();\n if (!isRecord(payload) || !Array.isArray(payload.keys)) {\n throw accessiAuthError(503, \"AUTH_JWKS_UNAVAILABLE\", \"Risposta JWKS non valida.\");\n }\n return payload.keys.filter(isRecord);\n } catch (error) {\n if (error && typeof error === \"object\" && \"code\" in error && \"status\" in error) {\n throw error;\n }\n throw accessiAuthError(503, \"AUTH_JWKS_UNAVAILABLE\", \"JWKS non raggiungibile.\");\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction selectJwk(\n keys: Array<Record<string, unknown>>,\n kid: string | undefined,\n algorithm: string,\n): JsonWebKey {\n const candidates = keys.filter((key) => {\n const keyAlg = typeof key.alg === \"string\" ? key.alg : undefined;\n const keyKid = typeof key.kid === \"string\" ? key.kid : undefined;\n if (keyAlg && keyAlg !== algorithm) return false;\n if (kid && keyKid && keyKid !== kid) return false;\n return true;\n });\n const selected = candidates[0];\n if (!selected) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Chiave JWKS non trovata per il token.\");\n }\n return selected as unknown as JsonWebKey;\n}\n\n/**\n * Crea un verificatore locale riutilizzabile.\n *\n * Supporta HMAC, chiavi pubbliche PEM (RS ed ES) e JWKS remoto. La cache\n * JWKS e legata all'istanza del verificatore.\n */\nexport function createAccessiTokenVerifier(options: AccessiResourceServerJwtOptions): AccessiTokenVerifier {\n const algorithms = defaultAlgorithms(options);\n if (algorithms.length === 0) {\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"Configurare almeno una tra jwt.secret, jwt.serverSecret, jwt.publicKey e jwt.jwks.\",\n );\n }\n\n const clockTolerance = options.clockToleranceSeconds ?? 5;\n const hmacSecret = options.secret\n ?? (options.serverSecret ? deriveAccessiAccessSecret(options.serverSecret) : undefined);\n let jwksCache: JwksCacheEntry | undefined;\n\n const getJwksKeys = async (): Promise<Array<Record<string, unknown>>> => {\n if (!options.jwks) return [];\n if (jwksCache && jwksCache.expiresAt > Date.now()) return jwksCache.keys;\n const keys = await fetchJwks(options.jwks);\n jwksCache = {\n keys,\n expiresAt: Date.now() + Math.max(1_000, options.jwks.cacheTtlMs ?? 300_000),\n };\n return keys;\n };\n\n const verify = async (token: string): Promise<AccessiTokenVerification> => {\n const decoded = jwt.decode(token, { complete: true });\n if (!decoded || typeof decoded === \"string\" || !isRecord(decoded.header)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token JWT non valido.\");\n }\n\n const algorithm = typeof decoded.header.alg === \"string\" ? decoded.header.alg : undefined;\n if (!algorithm || !algorithms.includes(algorithm as AccessiJwtAlgorithm)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Algoritmo JWT non consentito.\");\n }\n\n let key: jwt.Secret;\n if (algorithmFamily(algorithm) === \"hmac\") {\n if (!hmacSecret) {\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"jwt.secret o jwt.serverSecret non configurato per token HS*.\",\n );\n }\n key = hmacSecret;\n } else if (options.publicKey) {\n key = options.publicKey;\n } else if (options.jwks) {\n const keys = await getJwksKeys();\n const kid = typeof decoded.header.kid === \"string\" ? decoded.header.kid : undefined;\n key = createPublicKey({ key: selectJwk(keys, kid, algorithm), format: \"jwk\" })\n .export({ type: \"spki\", format: \"pem\" });\n } else {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"jwt.publicKey/jwt.jwks non configurati.\");\n }\n\n let verified: unknown;\n try {\n verified = jwt.verify(token, key, {\n algorithms: [algorithm as jwt.Algorithm],\n ...(options.issuer ? { issuer: options.issuer } : {}),\n ...(options.audience\n ? { audience: options.audience as jwt.VerifyOptions[\"audience\"] }\n : {}),\n clockTolerance,\n });\n } catch {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido o scaduto.\");\n }\n\n if (!isRecord(verified)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Payload JWT non valido.\");\n }\n if (verified.typ !== \"access\") {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Il token non e un access token Accessi.\");\n }\n\n const codiceUtente = resolveCodiceUtenteFromTokenPayload(verified);\n if (!codiceUtente) {\n throw accessiAuthError(401, \"AUTH_USER_CODE_MISSING\", \"Token privo di un utente valido.\");\n }\n\n return {\n token,\n payload: verified as AccessiAccessTokenPayload,\n codiceUtente,\n user: extractUser(verified),\n };\n };\n\n return {\n verify,\n async verifyAuthorizationHeader(header: unknown): Promise<AccessiTokenVerification> {\n const token = extractAccessiBearerToken(header);\n if (!token) {\n throw accessiAuthError(401, \"AUTH_TOKEN_MISSING\", \"Token Bearer mancante o malformato.\");\n }\n return verify(token);\n },\n };\n}\n\n/** Converte un header `Authorization` in verifica del token, senza cache JWKS condivisa. */\nexport async function verifyAccessiAccessToken(\n header: unknown,\n options: AccessiResourceServerJwtOptions,\n): Promise<AccessiTokenVerification> {\n return createAccessiTokenVerifier(options).verifyAuthorizationHeader(header);\n}\n"]}
@@ -0,0 +1,78 @@
1
+ import type { AccessiAuthorizationOptions, AccessiGrant, GrantsResult } from "../contracts";
2
+ /** Algoritmi JWT supportati dal resource server. */
3
+ export type AccessiJwtAlgorithm = "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512" | "ES256" | "ES384" | "ES512";
4
+ /** Opzioni di verifica locale del JWT. Almeno una tra `secret`, `publicKey` e `jwks` e obbligatoria. */
5
+ export interface AccessiResourceServerJwtOptions {
6
+ /** Chiave HMAC gia derivata (access key). Alternativa a `serverSecret`. */
7
+ secret?: string;
8
+ /**
9
+ * Segreto Accessi grezzo (`ACCESSI_JWT_SECRET`).
10
+ *
11
+ * Il resource server deriva automaticamente la chiave access con la stessa
12
+ * KDF del server: e il modo consigliato quando si condivide il segreto HS256.
13
+ */
14
+ serverSecret?: string;
15
+ /** Chiave pubblica PEM per algoritmi RS ed ES. */
16
+ publicKey?: string | Buffer;
17
+ /** JWKS remoto per verificare token firmati con chiavi asimmetriche. */
18
+ jwks?: {
19
+ url: string;
20
+ cacheTtlMs?: number;
21
+ timeoutMs?: number;
22
+ fetch?: typeof fetch;
23
+ };
24
+ /** Default: HS256 con `secret`, altrimenti RS/ES con `publicKey`/`jwks`. */
25
+ algorithms?: AccessiJwtAlgorithm[];
26
+ /** Issuer atteso (`iss`). */
27
+ issuer?: string;
28
+ /** Audience attesa (`aud`). */
29
+ audience?: string | string[];
30
+ /** Tolleranza orologio in secondi. Default: 5. */
31
+ clockToleranceSeconds?: number;
32
+ }
33
+ /** Configurazione del client di introspection verso Accessi Service. */
34
+ export interface AccessiIntrospectionOptions {
35
+ /** URL completo, es. `https://accessi.example.com/api/accessi/auth/introspect`. */
36
+ url: string;
37
+ /** Service token Accessi con scope `accessi:introspect`. */
38
+ serviceToken: string;
39
+ /** TTL della cache locale dei risultati attivi. Default: 30000 ms. */
40
+ cacheTtlMs?: number;
41
+ /** Timeout HTTP. Default: 3000 ms. */
42
+ timeoutMs?: number;
43
+ /** Fetch iniettabile per test o runtime non-Node. */
44
+ fetch?: typeof fetch;
45
+ }
46
+ /** Risultato dell'introspection. */
47
+ export interface AccessiIntrospectionResult {
48
+ active: boolean;
49
+ user?: Record<string, unknown>;
50
+ codiceUtente?: number;
51
+ grants?: GrantsResult;
52
+ }
53
+ /** Modalita di autenticazione del resource server. */
54
+ export type AccessiResourceServerMode = "local" | "introspection";
55
+ /**
56
+ * Configurazione di un backend fratello che non possiede il database Accessi.
57
+ *
58
+ * - `mode: "local"` verifica il JWT con chiave locale e, se servono grant, usa
59
+ * l'introspection per leggerli.
60
+ * - `mode: "introspection"` delega la verifica del token ad Accessi Service.
61
+ */
62
+ export interface AccessiResourceServerOptions {
63
+ mode?: AccessiResourceServerMode;
64
+ jwt?: AccessiResourceServerJwtOptions;
65
+ introspection?: AccessiIntrospectionOptions;
66
+ /** Policy di autorizzazione opzionale applicata dopo l'autenticazione. */
67
+ authorization?: AccessiAuthorizationOptions;
68
+ }
69
+ /** Dati allegati alla request dopo l'autenticazione. */
70
+ export interface AccessiRequestContext {
71
+ token: string;
72
+ user: Record<string, unknown>;
73
+ codiceUtente?: number;
74
+ grants?: GrantsResult;
75
+ payload?: Record<string, unknown>;
76
+ }
77
+ /** Grant esposto per compatibilita con il middleware storico. */
78
+ export type AccessiRequestGrants = AccessiGrant[];
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccessiAuthorizationOptions,\n AccessiGrant,\n GrantsResult,\n} from \"../contracts\";\n\n/** Algoritmi JWT supportati dal resource server. */\nexport type AccessiJwtAlgorithm =\n | \"HS256\"\n | \"HS384\"\n | \"HS512\"\n | \"RS256\"\n | \"RS384\"\n | \"RS512\"\n | \"ES256\"\n | \"ES384\"\n | \"ES512\";\n\n/** Opzioni di verifica locale del JWT. Almeno una tra `secret`, `publicKey` e `jwks` e obbligatoria. */\nexport interface AccessiResourceServerJwtOptions {\n /** Chiave HMAC gia derivata (access key). Alternativa a `serverSecret`. */\n secret?: string;\n /**\n * Segreto Accessi grezzo (`ACCESSI_JWT_SECRET`).\n *\n * Il resource server deriva automaticamente la chiave access con la stessa\n * KDF del server: e il modo consigliato quando si condivide il segreto HS256.\n */\n serverSecret?: string;\n /** Chiave pubblica PEM per algoritmi RS ed ES. */\n publicKey?: string | Buffer;\n /** JWKS remoto per verificare token firmati con chiavi asimmetriche. */\n jwks?: {\n url: string;\n cacheTtlMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n };\n /** Default: HS256 con `secret`, altrimenti RS/ES con `publicKey`/`jwks`. */\n algorithms?: AccessiJwtAlgorithm[];\n /** Issuer atteso (`iss`). */\n issuer?: string;\n /** Audience attesa (`aud`). */\n audience?: string | string[];\n /** Tolleranza orologio in secondi. Default: 5. */\n clockToleranceSeconds?: number;\n}\n\n/** Configurazione del client di introspection verso Accessi Service. */\nexport interface AccessiIntrospectionOptions {\n /** URL completo, es. `https://accessi.example.com/api/accessi/auth/introspect`. */\n url: string;\n /** Service token Accessi con scope `accessi:introspect`. */\n serviceToken: string;\n /** TTL della cache locale dei risultati attivi. Default: 30000 ms. */\n cacheTtlMs?: number;\n /** Timeout HTTP. Default: 3000 ms. */\n timeoutMs?: number;\n /** Fetch iniettabile per test o runtime non-Node. */\n fetch?: typeof fetch;\n}\n\n/** Risultato dell'introspection. */\nexport interface AccessiIntrospectionResult {\n active: boolean;\n user?: Record<string, unknown>;\n codiceUtente?: number;\n grants?: GrantsResult;\n}\n\n/** Modalita di autenticazione del resource server. */\nexport type AccessiResourceServerMode = \"local\" | \"introspection\";\n\n/**\n * Configurazione di un backend fratello che non possiede il database Accessi.\n *\n * - `mode: \"local\"` verifica il JWT con chiave locale e, se servono grant, usa\n * l'introspection per leggerli.\n * - `mode: \"introspection\"` delega la verifica del token ad Accessi Service.\n */\nexport interface AccessiResourceServerOptions {\n mode?: AccessiResourceServerMode;\n jwt?: AccessiResourceServerJwtOptions;\n introspection?: AccessiIntrospectionOptions;\n /** Policy di autorizzazione opzionale applicata dopo l'autenticazione. */\n authorization?: AccessiAuthorizationOptions;\n}\n\n/** Dati allegati alla request dopo l'autenticazione. */\nexport interface AccessiRequestContext {\n token: string;\n user: Record<string, unknown>;\n codiceUtente?: number;\n grants?: GrantsResult;\n payload?: Record<string, unknown>;\n}\n\n/** Grant esposto per compatibilita con il middleware storico. */\nexport type AccessiRequestGrants = AccessiGrant[];\n"]}