emilsoftware-utilities 2.0.0-dev.75 → 2.0.0-dev.77

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 (45) hide show
  1. package/dist/accessi-module/AccessiModule.d.ts +8 -1
  2. package/dist/accessi-module/AccessiModule.js.map +1 -1
  3. package/dist/accessi-module/Console/accessiFetch.d.ts +7 -0
  4. package/dist/accessi-module/Console/accessiFetch.js +45 -7
  5. package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
  6. package/dist/accessi-module/Console/console.js +84 -24
  7. package/dist/accessi-module/Console/console.js.map +1 -1
  8. package/dist/accessi-module/Console/generated/model/getUserByTokenRequest.d.ts +2 -2
  9. package/dist/accessi-module/Console/generated/model/getUserByTokenRequest.js.map +1 -1
  10. package/dist/accessi-module/Console/generated/model/refreshTokenRequest.d.ts +2 -2
  11. package/dist/accessi-module/Console/generated/model/refreshTokenRequest.js.map +1 -1
  12. package/dist/accessi-module/Console/index.html +1 -1
  13. package/dist/accessi-module/Console/wiki.js +3 -2
  14. package/dist/accessi-module/Console/wiki.js.map +1 -1
  15. package/dist/accessi-module/Controllers/AccessiConsoleController.d.ts +5 -3
  16. package/dist/accessi-module/Controllers/AccessiConsoleController.js +47 -12
  17. package/dist/accessi-module/Controllers/AccessiConsoleController.js.map +1 -1
  18. package/dist/accessi-module/Controllers/AuthController.js +35 -7
  19. package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
  20. package/dist/accessi-module/Controllers/ConsoleEntryController.js +8 -0
  21. package/dist/accessi-module/Controllers/ConsoleEntryController.js.map +1 -1
  22. package/dist/accessi-module/Dtos/GetUserByTokenRequest.d.ts +1 -1
  23. package/dist/accessi-module/Dtos/GetUserByTokenRequest.js +3 -2
  24. package/dist/accessi-module/Dtos/GetUserByTokenRequest.js.map +1 -1
  25. package/dist/accessi-module/Dtos/RefreshTokenDtos.d.ts +1 -1
  26. package/dist/accessi-module/Dtos/RefreshTokenDtos.js +4 -1
  27. package/dist/accessi-module/Dtos/RefreshTokenDtos.js.map +1 -1
  28. package/dist/accessi-module/index.d.ts +4 -0
  29. package/dist/accessi-module/index.js +30 -14
  30. package/dist/accessi-module/index.js.map +1 -1
  31. package/dist/accessi-module/security/authCookies.d.ts +104 -0
  32. package/dist/accessi-module/security/authCookies.js +240 -0
  33. package/dist/accessi-module/security/authCookies.js.map +1 -0
  34. package/dist/accessi-module/security/securityHeaders.d.ts +89 -0
  35. package/dist/accessi-module/security/securityHeaders.js +155 -0
  36. package/dist/accessi-module/security/securityHeaders.js.map +1 -0
  37. package/dist/accessi-module/security/validateOptions.js +34 -0
  38. package/dist/accessi-module/security/validateOptions.js.map +1 -1
  39. package/dist/emilsoftware-utilities-2.0.0-dev.77.tgz +0 -0
  40. package/dist/initEmilsoftwareModule.js +13 -11
  41. package/dist/initEmilsoftwareModule.js.map +1 -1
  42. package/docs/auth-cookies.md +123 -0
  43. package/docs/security-headers.md +151 -0
  44. package/package.json +3 -3
  45. package/dist/emilsoftware-utilities-2.0.0-dev.75.tgz +0 -0
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.isValidAdminBootstrapToken = exports.clearAdminBootstrapToken = exports.getAdminBootstrapToken = exports.getOrCreateAdminBootstrapToken = exports.AdminBootstrapService = exports.SchemaExportService = exports.ServiceTokenService = exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.leadingStatementKeyword = exports.analyzeCatalogScript = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.revokeAccessiAccessTokenIfConfigured = exports.revokeAccessiAccessToken = exports.isAccessiAccessTokenRevoked = exports.getAccessTokenRevocationStore = exports.createRedisAccessTokenRevocationStore = exports.createMemoryAccessTokenRevocationStore = exports.revokeRefreshTokenFamily = exports.isRefreshTokenFamilyRevoked = exports.getRefreshTokenRotationStore = exports.consumeRefreshToken = exports.createRedisRefreshTokenRotationStore = exports.createMemoryRefreshTokenRotationStore = exports.getSessionRevocationStore = exports.isAccessiTokenRevoked = exports.revokeAccessiUserSessionsIfConfigured = exports.revokeAccessiUserSessions = exports.createRedisSessionRevocationStore = exports.createMemorySessionRevocationStore = exports.auditAccessi = exports.validateAccessiOptions = exports.assertValidAccessiOptions = exports.createAccessiEdgeRateLimitMiddleware = exports.getDefaultRateLimitStore = exports.createRedisRateLimitStore = exports.createMemoryRateLimitStore = exports.getDefaultConsoleEntryStore = exports.createRedisConsoleEntryStore = exports.createMemoryConsoleEntryStore = exports.AccessiDatabaseUpdater = exports.FederatedAuthExchangeController = exports.AccessiIntrospectionController = exports.AccessiModule = void 0;
30
- exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.verifyAccessiJwt = exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = void 0;
30
+ exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.verifyAccessiJwt = exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.isAccessiCsrfExemptPath = exports.parseAccessiCookieHeader = exports.applyAccessiAuthCookies = exports.clearAccessiAuthCookies = exports.setAccessiAuthCookies = exports.getAccessiRefreshTokenFromCookie = exports.getAccessiAccessTokenFromCookie = exports.resolveAccessiAuthCookieOptions = exports.createAccessiAuthCookieMiddleware = exports.resolveAccessiSecurityHeaders = exports.createAccessiSecurityHeadersMiddleware = exports.buildAccessiContentSecurityPolicy = exports.applyAccessiContentSecurityPolicy = exports.applyAccessiBaseSecurityHeaders = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = void 0;
31
31
  exports.initializeAccessiModule = initializeAccessiModule;
32
32
  const express_1 = __importDefault(require("express"));
33
33
  const core_1 = require("@nestjs/core");
@@ -44,6 +44,8 @@ const AccessiHttpExceptionFilter_1 = require("./security/AccessiHttpExceptionFil
44
44
  const emailConfiguration_1 = require("./security/emailConfiguration");
45
45
  const jwks_1 = require("./security/jwks");
46
46
  const edgeRateLimit_1 = require("./security/edgeRateLimit");
47
+ const securityHeaders_1 = require("./security/securityHeaders");
48
+ const authCookies_1 = require("./security/authCookies");
47
49
  function describeDatabaseTarget(options) {
48
50
  var _a, _b, _c, _d;
49
51
  const dbOptions = options.databaseOptions;
@@ -64,7 +66,7 @@ function describeDatabaseTarget(options) {
64
66
  */
65
67
  function initializeAccessiModule(app, options) {
66
68
  return __awaiter(this, void 0, void 0, function* () {
67
- var _a, _b, _c, _d, _e, _f;
69
+ var _a, _b, _c, _d, _e, _f, _g;
68
70
  // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.
69
71
  (0, emailConfiguration_1.assertEmailConfigured)(options);
70
72
  const logger = new Logger_1.Logger("initializeAccessiModule");
@@ -91,17 +93,15 @@ function initializeAccessiModule(app, options) {
91
93
  if (edgeRateLimit) {
92
94
  app.use(edgeRateLimit);
93
95
  }
96
+ const authCookie = (0, authCookies_1.createAccessiAuthCookieMiddleware)(options, isAccessiRoute);
97
+ if (authCookie) {
98
+ app.use(authCookie);
99
+ }
94
100
  if (((_c = options.http) === null || _c === void 0 ? void 0 : _c.securityHeaders) !== false) {
95
- app.use((req, res, next) => {
96
- if (!isAccessiRoute(req.path)) {
97
- return next();
98
- }
99
- res.setHeader('X-Content-Type-Options', 'nosniff');
100
- res.setHeader('X-Frame-Options', 'SAMEORIGIN');
101
- res.setHeader('Referrer-Policy', 'no-referrer');
102
- res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
103
- return next();
104
- });
101
+ const securityHeaders = (0, securityHeaders_1.createAccessiSecurityHeadersMiddleware)((_d = options.http) === null || _d === void 0 ? void 0 : _d.securityHeaders, isAccessiRoute, { isOpenApiUi: (path) => (0, OpenApiConfig_1.isOpenApiRequestPath)(path, resolvedOpenApi) });
102
+ if (securityHeaders) {
103
+ app.use(securityHeaders);
104
+ }
105
105
  }
106
106
  app.use((req, res, next) => {
107
107
  if (!isAccessiRoute(req.path)) {
@@ -116,8 +116,8 @@ function initializeAccessiModule(app, options) {
116
116
  const nestExpressInstance = new platform_express_1.ExpressAdapter(nestHostApp);
117
117
  const nestApp = yield core_1.NestFactory.create(AccessiModule_1.AccessiModule.forRoot(options), nestExpressInstance, Object.assign({ bufferLogs: options.bufferLogs !== false }, (options.logger ? { logger: options.logger } : {})));
118
118
  logger.info("Applicazione Nest accessi creata.");
119
- if (((_d = options.http) === null || _d === void 0 ? void 0 : _d.cors) !== false) {
120
- nestApp.enableCors((_f = (_e = options.http) === null || _e === void 0 ? void 0 : _e.cors) !== null && _f !== void 0 ? _f : { exposedHeaders: ['X-Total-Count'] });
119
+ if (((_e = options.http) === null || _e === void 0 ? void 0 : _e.cors) !== false) {
120
+ nestApp.enableCors((_g = (_f = options.http) === null || _f === void 0 ? void 0 : _f.cors) !== null && _g !== void 0 ? _g : { exposedHeaders: ['X-Total-Count', 'X-CSRF-Token'] });
121
121
  }
122
122
  nestApp.useGlobalPipes((0, accessiValidation_1.createAccessiValidationPipe)());
123
123
  nestApp.useGlobalFilters(new AccessiHttpExceptionFilter_1.AccessiHttpExceptionFilter());
@@ -232,6 +232,22 @@ Object.defineProperty(exports, "buildAccessiJwks", { enumerable: true, get: func
232
232
  Object.defineProperty(exports, "createAccessiJwksHandler", { enumerable: true, get: function () { return jwks_2.createAccessiJwksHandler; } });
233
233
  Object.defineProperty(exports, "getAccessiJwksPath", { enumerable: true, get: function () { return jwks_2.getAccessiJwksPath; } });
234
234
  Object.defineProperty(exports, "setupAccessiJwks", { enumerable: true, get: function () { return jwks_2.setupAccessiJwks; } });
235
+ var securityHeaders_2 = require("./security/securityHeaders");
236
+ Object.defineProperty(exports, "applyAccessiBaseSecurityHeaders", { enumerable: true, get: function () { return securityHeaders_2.applyAccessiBaseSecurityHeaders; } });
237
+ Object.defineProperty(exports, "applyAccessiContentSecurityPolicy", { enumerable: true, get: function () { return securityHeaders_2.applyAccessiContentSecurityPolicy; } });
238
+ Object.defineProperty(exports, "buildAccessiContentSecurityPolicy", { enumerable: true, get: function () { return securityHeaders_2.buildAccessiContentSecurityPolicy; } });
239
+ Object.defineProperty(exports, "createAccessiSecurityHeadersMiddleware", { enumerable: true, get: function () { return securityHeaders_2.createAccessiSecurityHeadersMiddleware; } });
240
+ Object.defineProperty(exports, "resolveAccessiSecurityHeaders", { enumerable: true, get: function () { return securityHeaders_2.resolveAccessiSecurityHeaders; } });
241
+ var authCookies_2 = require("./security/authCookies");
242
+ Object.defineProperty(exports, "createAccessiAuthCookieMiddleware", { enumerable: true, get: function () { return authCookies_2.createAccessiAuthCookieMiddleware; } });
243
+ Object.defineProperty(exports, "resolveAccessiAuthCookieOptions", { enumerable: true, get: function () { return authCookies_2.resolveAccessiAuthCookieOptions; } });
244
+ Object.defineProperty(exports, "getAccessiAccessTokenFromCookie", { enumerable: true, get: function () { return authCookies_2.getAccessiAccessTokenFromCookie; } });
245
+ Object.defineProperty(exports, "getAccessiRefreshTokenFromCookie", { enumerable: true, get: function () { return authCookies_2.getAccessiRefreshTokenFromCookie; } });
246
+ Object.defineProperty(exports, "setAccessiAuthCookies", { enumerable: true, get: function () { return authCookies_2.setAccessiAuthCookies; } });
247
+ Object.defineProperty(exports, "clearAccessiAuthCookies", { enumerable: true, get: function () { return authCookies_2.clearAccessiAuthCookies; } });
248
+ Object.defineProperty(exports, "applyAccessiAuthCookies", { enumerable: true, get: function () { return authCookies_2.applyAccessiAuthCookies; } });
249
+ Object.defineProperty(exports, "parseAccessiCookieHeader", { enumerable: true, get: function () { return authCookies_2.parseAccessiCookieHeader; } });
250
+ Object.defineProperty(exports, "isAccessiCsrfExemptPath", { enumerable: true, get: function () { return authCookies_2.isAccessiCsrfExemptPath; } });
235
251
  var jwtTokenOptions_1 = require("./security/jwtTokenOptions");
236
252
  Object.defineProperty(exports, "getAccessiAccessTokenSigningConfig", { enumerable: true, get: function () { return jwtTokenOptions_1.getAccessiAccessTokenSigningConfig; } });
237
253
  Object.defineProperty(exports, "getAccessiAccessTokenVerificationConfig", { enumerable: true, get: function () { return jwtTokenOptions_1.getAccessiAccessTokenVerificationConfig; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n if (options.http?.securityHeaders !== false) {\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'SAMEORIGIN');\n res.setHeader('Referrer-Policy', 'no-referrer');\n res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');\n return next();\n });\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport { auditAccessi } from './security/audit';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nimport { createAccessiSecurityHeadersMiddleware } from './security/securityHeaders';\nimport { createAccessiAuthCookieMiddleware } from './security/authCookies';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n const authCookie = createAccessiAuthCookieMiddleware(options, isAccessiRoute);\n if (authCookie) {\n app.use(authCookie);\n }\n if (options.http?.securityHeaders !== false) {\n const securityHeaders = createAccessiSecurityHeadersMiddleware(\n options.http?.securityHeaders,\n isAccessiRoute,\n { isOpenApiUi: (path) => isOpenApiRequestPath(path, resolvedOpenApi) },\n );\n if (securityHeaders) {\n app.use(securityHeaders);\n }\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count', 'X-CSRF-Token'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport { auditAccessi } from './security/audit';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n applyAccessiBaseSecurityHeaders,\n applyAccessiContentSecurityPolicy,\n buildAccessiContentSecurityPolicy,\n createAccessiSecurityHeadersMiddleware,\n resolveAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport type {\n AccessiCspDirectives,\n AccessiCspOptions,\n AccessiCspSurface,\n AccessiSecurityHeadersOptions,\n AccessiSecurityHeadersSetting,\n ResolvedAccessiCsp,\n ResolvedAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport {\n createAccessiAuthCookieMiddleware,\n resolveAccessiAuthCookieOptions,\n getAccessiAccessTokenFromCookie,\n getAccessiRefreshTokenFromCookie,\n setAccessiAuthCookies,\n clearAccessiAuthCookies,\n applyAccessiAuthCookies,\n parseAccessiCookieHeader,\n isAccessiCsrfExemptPath\n} from './security/authCookies';\nexport type {\n AccessiAuthCookieOptions,\n AccessiAuthCookieSetting,\n AccessiAuthTokenPair,\n ResolvedAccessiAuthCookieOptions\n} from './security/authCookies';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}
@@ -0,0 +1,104 @@
1
+ import type { NextFunction, Request, Response } from 'express';
2
+ import type { AccessiOptions } from '../AccessiModule';
3
+ /** Modalita di autenticazione via cookie httpOnly. */
4
+ export interface AccessiAuthCookieOptions {
5
+ /** Default `true`: la sola presenza dell'oggetto abilita la modalita cookie. */
6
+ enabled?: boolean;
7
+ /** `Secure` sui cookie. Default `true`; disattivare solo in sviluppo locale HTTP. */
8
+ secure?: boolean;
9
+ /** Default `lax`. Per SPA su altro dominio serve `none` insieme a `secure: true`. */
10
+ sameSite?: 'strict' | 'lax' | 'none';
11
+ /** Dominio dei cookie, opzionale. */
12
+ domain?: string;
13
+ /** Nome del cookie con l'access token. Default `accessi_access`. */
14
+ accessTokenName?: string;
15
+ /** Nome del cookie con il refresh token. Default `accessi_refresh`. */
16
+ refreshTokenName?: string;
17
+ /** Nome del cookie CSRF leggibile dal client. Default `accessi_csrf`. */
18
+ csrfTokenName?: string;
19
+ /** Path del cookie access. Default `/api/accessi`. */
20
+ accessPath?: string;
21
+ /** Path del cookie refresh. Default `/api/accessi/auth`. */
22
+ refreshPath?: string;
23
+ /** Path del cookie CSRF. Default `/`. */
24
+ csrfPath?: string;
25
+ /** Header CSRF richiesto. Default `x-csrf-token`. */
26
+ csrfHeaderName?: string;
27
+ /** `double-submit` (default) oppure `off` per host che gestiscono CSRF altrove. */
28
+ csrf?: 'double-submit' | 'off';
29
+ /**
30
+ * Restituisce comunque i token nel body JSON. Default `false`: in modalita
31
+ * cookie i token restano solo negli header httpOnly.
32
+ */
33
+ exposeTokens?: boolean;
34
+ /** Legge il refresh token dal cookie quando il body non lo contiene. Default `true`. */
35
+ refreshFromCookie?: boolean;
36
+ }
37
+ export type AccessiAuthCookieSetting = AccessiAuthCookieOptions;
38
+ export interface ResolvedAccessiAuthCookieOptions {
39
+ secure: boolean;
40
+ sameSite: 'strict' | 'lax' | 'none';
41
+ domain?: string;
42
+ accessTokenName: string;
43
+ refreshTokenName: string;
44
+ csrfTokenName: string;
45
+ accessPath: string;
46
+ refreshPath: string;
47
+ csrfPath: string;
48
+ csrfHeaderName: string;
49
+ csrf: 'double-submit' | 'off';
50
+ exposeTokens: boolean;
51
+ refreshFromCookie: boolean;
52
+ }
53
+ export interface AccessiAuthTokenPair {
54
+ access?: string;
55
+ refresh?: string;
56
+ }
57
+ /** Risolve la configurazione dei cookie; `undefined` quando la modalita e disattivata. */
58
+ export declare function resolveAccessiAuthCookieOptions(options: Pick<AccessiOptions, 'authCookie'>): ResolvedAccessiAuthCookieOptions | undefined;
59
+ /** Legge i cookie senza aggiungere la dipendenza `cookie-parser`. */
60
+ export declare function parseAccessiCookieHeader(header: string | undefined): Record<string, string>;
61
+ /** True per richieste che modificano stato (dove serve il CSRF). */
62
+ export declare function isAccessiUnsafeMethod(method: string): boolean;
63
+ /** True per gli endpoint pubblici esenti da CSRF. */
64
+ export declare function isAccessiCsrfExemptPath(path: string): boolean;
65
+ /** Imposta i cookie access, refresh e (se assente) CSRF. */
66
+ export declare function setAccessiAuthCookies(res: Pick<Response, 'append'>, config: ResolvedAccessiAuthCookieOptions, tokens: AccessiAuthTokenPair): void;
67
+ /** Cancella i cookie di sessione (logout/revoca). */
68
+ export declare function clearAccessiAuthCookies(res: Pick<Response, 'append'>, config: ResolvedAccessiAuthCookieOptions): void;
69
+ export interface AccessiAuthTokenValue {
70
+ value?: string;
71
+ }
72
+ /** Forma comune dei risultati di auth: stringa o `TokenResult` di Accessi. */
73
+ export interface AccessiAuthResultLike {
74
+ token?: string | AccessiAuthTokenValue;
75
+ refreshToken?: string | AccessiAuthTokenValue;
76
+ }
77
+ /**
78
+ * Prepara la risposta di login/refresh: imposta i cookie e rimuove i token dal
79
+ * body quando la modalita cookie non prevede `exposeTokens`.
80
+ */
81
+ export declare function applyAccessiAuthCookies<T extends AccessiAuthResultLike>(res: Pick<Response, 'append'>, config: ResolvedAccessiAuthCookieOptions | undefined, result: T): T;
82
+ /** Rimuove i token dal `LoginResult` quando la modalita cookie li nasconde. */
83
+ export declare function hideAccessiLoginTokens(config: ResolvedAccessiAuthCookieOptions | undefined, result: {
84
+ token?: unknown;
85
+ refreshToken?: unknown;
86
+ }): void;
87
+ /** Legge l'access token dal cookie (per test e per host senza middleware). */
88
+ export declare function getAccessiAccessTokenFromCookie(header: string | undefined, config: ResolvedAccessiAuthCookieOptions): string | undefined;
89
+ /** Legge il refresh token dal cookie. */
90
+ export declare function getAccessiRefreshTokenFromCookie(header: string | undefined, config: ResolvedAccessiAuthCookieOptions): string | undefined;
91
+ /**
92
+ * Middleware della modalita cookie.
93
+ *
94
+ * - copia l'access token dal cookie nell'header `Authorization`, cosi guard,
95
+ * middleware e controller esistenti funzionano senza modifiche;
96
+ * - garantisce un cookie CSRF double-submit leggibile dal client;
97
+ * - blocca le richieste autenticate via cookie che modificano stato senza
98
+ * l'header CSRF, salvo endpoint pubblici di bootstrap della sessione.
99
+ */
100
+ export declare function createAccessiAuthCookieMiddleware(options: Pick<AccessiOptions, 'authCookie'>, isAccessiRoute: (path: string) => boolean): ((req: Request, res: Response, next: NextFunction) => void) | undefined;
101
+ /** True se il nome cookie e valido per l'header `Set-Cookie`. */
102
+ export declare function isValidAccessiCookieName(name: string): boolean;
103
+ /** Helpers per le combinazioni di cookie supportate (usati dalla validazione). */
104
+ export declare function accessiCookieNames(config: ResolvedAccessiAuthCookieOptions): string[];
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAccessiAuthCookieOptions = resolveAccessiAuthCookieOptions;
4
+ exports.parseAccessiCookieHeader = parseAccessiCookieHeader;
5
+ exports.isAccessiUnsafeMethod = isAccessiUnsafeMethod;
6
+ exports.isAccessiCsrfExemptPath = isAccessiCsrfExemptPath;
7
+ exports.setAccessiAuthCookies = setAccessiAuthCookies;
8
+ exports.clearAccessiAuthCookies = clearAccessiAuthCookies;
9
+ exports.applyAccessiAuthCookies = applyAccessiAuthCookies;
10
+ exports.hideAccessiLoginTokens = hideAccessiLoginTokens;
11
+ exports.getAccessiAccessTokenFromCookie = getAccessiAccessTokenFromCookie;
12
+ exports.getAccessiRefreshTokenFromCookie = getAccessiRefreshTokenFromCookie;
13
+ exports.createAccessiAuthCookieMiddleware = createAccessiAuthCookieMiddleware;
14
+ exports.isValidAccessiCookieName = isValidAccessiCookieName;
15
+ exports.accessiCookieNames = accessiCookieNames;
16
+ const crypto_1 = require("crypto");
17
+ const jsonwebtoken_1 = require("jsonwebtoken");
18
+ const COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
19
+ const DEFAULTS = {
20
+ secure: true,
21
+ sameSite: 'lax',
22
+ accessTokenName: 'accessi_access',
23
+ refreshTokenName: 'accessi_refresh',
24
+ csrfTokenName: 'accessi_csrf',
25
+ accessPath: '/api/accessi',
26
+ refreshPath: '/api/accessi/auth',
27
+ csrfPath: '/',
28
+ csrfHeaderName: 'x-csrf-token',
29
+ csrf: 'double-submit',
30
+ exposeTokens: false,
31
+ refreshFromCookie: true,
32
+ };
33
+ /** Percorsi pubblici che non richiedono il token CSRF (non hanno ancora una sessione). */
34
+ const CSRF_EXEMPT_PATHS = [
35
+ '/api/accessi/auth/login',
36
+ '/api/accessi/auth/refresh',
37
+ '/api/accessi/auth/confirm-reset-password',
38
+ '/api/accessi/auth/two-factor/verify',
39
+ '/api/accessi/auth/two-factor/resend',
40
+ '/api/accessi/auth/bootstrap-admin',
41
+ '/api/accessi/email/',
42
+ '/api/accessi/federated-auth/exchange',
43
+ '/api/accessi/user/register',
44
+ ];
45
+ const UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
46
+ /** Risolve la configurazione dei cookie; `undefined` quando la modalita e disattivata. */
47
+ function resolveAccessiAuthCookieOptions(options) {
48
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
49
+ const raw = options.authCookie;
50
+ if (!raw || raw.enabled === false)
51
+ return undefined;
52
+ return Object.assign(Object.assign({ secure: raw.secure !== false, sameSite: (_a = raw.sameSite) !== null && _a !== void 0 ? _a : DEFAULTS.sameSite }, (raw.domain ? { domain: raw.domain } : {})), { accessTokenName: (_b = raw.accessTokenName) !== null && _b !== void 0 ? _b : DEFAULTS.accessTokenName, refreshTokenName: (_c = raw.refreshTokenName) !== null && _c !== void 0 ? _c : DEFAULTS.refreshTokenName, csrfTokenName: (_d = raw.csrfTokenName) !== null && _d !== void 0 ? _d : DEFAULTS.csrfTokenName, accessPath: (_e = raw.accessPath) !== null && _e !== void 0 ? _e : DEFAULTS.accessPath, refreshPath: (_f = raw.refreshPath) !== null && _f !== void 0 ? _f : DEFAULTS.refreshPath, csrfPath: (_g = raw.csrfPath) !== null && _g !== void 0 ? _g : DEFAULTS.csrfPath, csrfHeaderName: ((_h = raw.csrfHeaderName) !== null && _h !== void 0 ? _h : DEFAULTS.csrfHeaderName).toLowerCase(), csrf: (_j = raw.csrf) !== null && _j !== void 0 ? _j : DEFAULTS.csrf, exposeTokens: raw.exposeTokens === true, refreshFromCookie: raw.refreshFromCookie !== false });
53
+ }
54
+ /** Legge i cookie senza aggiungere la dipendenza `cookie-parser`. */
55
+ function parseAccessiCookieHeader(header) {
56
+ const cookies = {};
57
+ if (!header)
58
+ return cookies;
59
+ for (const part of header.split(';')) {
60
+ const separator = part.indexOf('=');
61
+ if (separator < 0)
62
+ continue;
63
+ const name = part.slice(0, separator).trim();
64
+ if (!name)
65
+ continue;
66
+ const rawValue = part.slice(separator + 1).trim();
67
+ try {
68
+ cookies[name] = decodeURIComponent(rawValue);
69
+ }
70
+ catch (_a) {
71
+ cookies[name] = rawValue;
72
+ }
73
+ }
74
+ return cookies;
75
+ }
76
+ /** True per richieste che modificano stato (dove serve il CSRF). */
77
+ function isAccessiUnsafeMethod(method) {
78
+ return UNSAFE_METHODS.has(method.toUpperCase());
79
+ }
80
+ /** True per gli endpoint pubblici esenti da CSRF. */
81
+ function isAccessiCsrfExemptPath(path) {
82
+ return CSRF_EXEMPT_PATHS.some((exempt) => exempt.endsWith('/') ? path.startsWith(exempt) : path === exempt);
83
+ }
84
+ function tokenMaxAgeSeconds(token) {
85
+ if (!token)
86
+ return undefined;
87
+ const decoded = (0, jsonwebtoken_1.decode)(token);
88
+ if (!decoded || typeof decoded === 'string')
89
+ return undefined;
90
+ const exp = Number(decoded.exp);
91
+ if (!Number.isFinite(exp))
92
+ return undefined;
93
+ return Math.max(0, Math.floor(exp - Date.now() / 1000));
94
+ }
95
+ function serializeCookie(name, value, options) {
96
+ const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`];
97
+ if (options.domain)
98
+ parts.push(`Domain=${options.domain}`);
99
+ if (options.maxAgeSeconds !== undefined)
100
+ parts.push(`Max-Age=${options.maxAgeSeconds}`);
101
+ if (options.httpOnly)
102
+ parts.push('HttpOnly');
103
+ if (options.secure)
104
+ parts.push('Secure');
105
+ const sameSite = { strict: 'Strict', lax: 'Lax', none: 'None' }[options.sameSite];
106
+ parts.push(`SameSite=${sameSite}`);
107
+ return parts.join('; ');
108
+ }
109
+ function appendCookie(res, cookie) {
110
+ res.append('Set-Cookie', cookie);
111
+ }
112
+ /** Imposta i cookie access, refresh e (se assente) CSRF. */
113
+ function setAccessiAuthCookies(res, config, tokens) {
114
+ if (tokens.access) {
115
+ appendCookie(res, serializeCookie(config.accessTokenName, tokens.access, Object.assign(Object.assign(Object.assign({ path: config.accessPath }, (tokenMaxAgeSeconds(tokens.access) !== undefined
116
+ ? { maxAgeSeconds: tokenMaxAgeSeconds(tokens.access) }
117
+ : {})), { httpOnly: true, secure: config.secure, sameSite: config.sameSite }), (config.domain ? { domain: config.domain } : {}))));
118
+ }
119
+ if (tokens.refresh) {
120
+ appendCookie(res, serializeCookie(config.refreshTokenName, tokens.refresh, Object.assign(Object.assign(Object.assign({ path: config.refreshPath }, (tokenMaxAgeSeconds(tokens.refresh) !== undefined
121
+ ? { maxAgeSeconds: tokenMaxAgeSeconds(tokens.refresh) }
122
+ : {})), { httpOnly: true, secure: config.secure, sameSite: config.sameSite }), (config.domain ? { domain: config.domain } : {}))));
123
+ }
124
+ }
125
+ /** Cancella i cookie di sessione (logout/revoca). */
126
+ function clearAccessiAuthCookies(res, config) {
127
+ for (const [name, path] of [
128
+ [config.accessTokenName, config.accessPath],
129
+ [config.refreshTokenName, config.refreshPath],
130
+ [config.csrfTokenName, config.csrfPath],
131
+ ]) {
132
+ appendCookie(res, serializeCookie(name, '', Object.assign({ path, maxAgeSeconds: 0, httpOnly: name !== config.csrfTokenName, secure: config.secure, sameSite: config.sameSite }, (config.domain ? { domain: config.domain } : {}))));
133
+ }
134
+ }
135
+ function accessiTokenValue(token) {
136
+ if (typeof token === 'string')
137
+ return token === '' ? undefined : token;
138
+ return token === null || token === void 0 ? void 0 : token.value;
139
+ }
140
+ /**
141
+ * Prepara la risposta di login/refresh: imposta i cookie e rimuove i token dal
142
+ * body quando la modalita cookie non prevede `exposeTokens`.
143
+ */
144
+ function applyAccessiAuthCookies(res, config, result) {
145
+ if (!config)
146
+ return result;
147
+ setAccessiAuthCookies(res, config, {
148
+ access: accessiTokenValue(result.token),
149
+ refresh: accessiTokenValue(result.refreshToken),
150
+ });
151
+ hideAccessiLoginTokens(config, result);
152
+ return result;
153
+ }
154
+ /** Rimuove i token dal `LoginResult` quando la modalita cookie li nasconde. */
155
+ function hideAccessiLoginTokens(config, result) {
156
+ if (!config || config.exposeTokens)
157
+ return;
158
+ delete result.token;
159
+ delete result.refreshToken;
160
+ }
161
+ /** Legge l'access token dal cookie (per test e per host senza middleware). */
162
+ function getAccessiAccessTokenFromCookie(header, config) {
163
+ return parseAccessiCookieHeader(header)[config.accessTokenName];
164
+ }
165
+ /** Legge il refresh token dal cookie. */
166
+ function getAccessiRefreshTokenFromCookie(header, config) {
167
+ return parseAccessiCookieHeader(header)[config.refreshTokenName];
168
+ }
169
+ function safeEqual(left, right) {
170
+ const a = Buffer.from(left);
171
+ const b = Buffer.from(right);
172
+ return a.length === b.length && (0, crypto_1.timingSafeEqual)(a, b);
173
+ }
174
+ function csrfError(res) {
175
+ res.status(403).json({
176
+ severity: 'error',
177
+ status: 403,
178
+ statusCode: 2,
179
+ code: 'AUTH_CSRF_INVALID',
180
+ error: 'AUTH_CSRF_INVALID',
181
+ message: 'Token CSRF mancante o non valido.',
182
+ });
183
+ }
184
+ /**
185
+ * Middleware della modalita cookie.
186
+ *
187
+ * - copia l'access token dal cookie nell'header `Authorization`, cosi guard,
188
+ * middleware e controller esistenti funzionano senza modifiche;
189
+ * - garantisce un cookie CSRF double-submit leggibile dal client;
190
+ * - blocca le richieste autenticate via cookie che modificano stato senza
191
+ * l'header CSRF, salvo endpoint pubblici di bootstrap della sessione.
192
+ */
193
+ function createAccessiAuthCookieMiddleware(options, isAccessiRoute) {
194
+ const config = resolveAccessiAuthCookieOptions(options);
195
+ if (!config)
196
+ return undefined;
197
+ return (req, res, next) => {
198
+ if (!isAccessiRoute(req.path)) {
199
+ next();
200
+ return;
201
+ }
202
+ const cookies = parseAccessiCookieHeader(req.headers.cookie);
203
+ let csrfToken = cookies[config.csrfTokenName];
204
+ if (!csrfToken && config.csrf === 'double-submit') {
205
+ csrfToken = (0, crypto_1.randomBytes)(32).toString('base64url');
206
+ appendCookie(res, serializeCookie(config.csrfTokenName, csrfToken, Object.assign({ path: config.csrfPath, httpOnly: false, secure: config.secure, sameSite: config.sameSite }, (config.domain ? { domain: config.domain } : {}))));
207
+ }
208
+ if (config.csrf === 'double-submit' && csrfToken) {
209
+ // Rende il token leggibile anche a una SPA su altra origine (via CORS,
210
+ // con `Access-Control-Expose-Headers: X-CSRF-Token`).
211
+ res.setHeader('X-CSRF-Token', csrfToken);
212
+ }
213
+ const accessToken = cookies[config.accessTokenName];
214
+ const hasAuthorization = typeof req.headers.authorization === 'string'
215
+ && req.headers.authorization.trim() !== '';
216
+ if (accessToken && !hasAuthorization) {
217
+ req.headers.authorization = `Bearer ${accessToken}`;
218
+ if (config.csrf === 'double-submit'
219
+ && isAccessiUnsafeMethod(req.method)
220
+ && !isAccessiCsrfExemptPath(req.path)) {
221
+ const headerValue = req.headers[config.csrfHeaderName];
222
+ const provided = Array.isArray(headerValue) ? headerValue[0] : headerValue;
223
+ if (!csrfToken || !provided || !safeEqual(provided, csrfToken)) {
224
+ csrfError(res);
225
+ return;
226
+ }
227
+ }
228
+ }
229
+ next();
230
+ };
231
+ }
232
+ /** True se il nome cookie e valido per l'header `Set-Cookie`. */
233
+ function isValidAccessiCookieName(name) {
234
+ return COOKIE_NAME.test(name);
235
+ }
236
+ /** Helpers per le combinazioni di cookie supportate (usati dalla validazione). */
237
+ function accessiCookieNames(config) {
238
+ return [config.accessTokenName, config.refreshTokenName, config.csrfTokenName];
239
+ }
240
+ //# sourceMappingURL=authCookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authCookies.js","sourceRoot":"","sources":["../../../src/accessi-module/security/authCookies.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes, timingSafeEqual } from 'crypto';\nimport type { NextFunction, Request, Response } from 'express';\nimport type * as jwt from 'jsonwebtoken';\nimport { decode as decodeJwt } from 'jsonwebtoken';\nimport type { AccessiOptions } from '../AccessiModule';\n\n/** Modalita di autenticazione via cookie httpOnly. */\nexport interface AccessiAuthCookieOptions {\n /** Default `true`: la sola presenza dell'oggetto abilita la modalita cookie. */\n enabled?: boolean;\n /** `Secure` sui cookie. Default `true`; disattivare solo in sviluppo locale HTTP. */\n secure?: boolean;\n /** Default `lax`. Per SPA su altro dominio serve `none` insieme a `secure: true`. */\n sameSite?: 'strict' | 'lax' | 'none';\n /** Dominio dei cookie, opzionale. */\n domain?: string;\n /** Nome del cookie con l'access token. Default `accessi_access`. */\n accessTokenName?: string;\n /** Nome del cookie con il refresh token. Default `accessi_refresh`. */\n refreshTokenName?: string;\n /** Nome del cookie CSRF leggibile dal client. Default `accessi_csrf`. */\n csrfTokenName?: string;\n /** Path del cookie access. Default `/api/accessi`. */\n accessPath?: string;\n /** Path del cookie refresh. Default `/api/accessi/auth`. */\n refreshPath?: string;\n /** Path del cookie CSRF. Default `/`. */\n csrfPath?: string;\n /** Header CSRF richiesto. Default `x-csrf-token`. */\n csrfHeaderName?: string;\n /** `double-submit` (default) oppure `off` per host che gestiscono CSRF altrove. */\n csrf?: 'double-submit' | 'off';\n /**\n * Restituisce comunque i token nel body JSON. Default `false`: in modalita\n * cookie i token restano solo negli header httpOnly.\n */\n exposeTokens?: boolean;\n /** Legge il refresh token dal cookie quando il body non lo contiene. Default `true`. */\n refreshFromCookie?: boolean;\n}\n\nexport type AccessiAuthCookieSetting = AccessiAuthCookieOptions;\n\nexport interface ResolvedAccessiAuthCookieOptions {\n secure: boolean;\n sameSite: 'strict' | 'lax' | 'none';\n domain?: string;\n accessTokenName: string;\n refreshTokenName: string;\n csrfTokenName: string;\n accessPath: string;\n refreshPath: string;\n csrfPath: string;\n csrfHeaderName: string;\n csrf: 'double-submit' | 'off';\n exposeTokens: boolean;\n refreshFromCookie: boolean;\n}\n\nexport interface AccessiAuthTokenPair {\n access?: string;\n refresh?: string;\n}\n\nconst COOKIE_NAME = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n\nconst DEFAULTS = {\n secure: true,\n sameSite: 'lax' as const,\n accessTokenName: 'accessi_access',\n refreshTokenName: 'accessi_refresh',\n csrfTokenName: 'accessi_csrf',\n accessPath: '/api/accessi',\n refreshPath: '/api/accessi/auth',\n csrfPath: '/',\n csrfHeaderName: 'x-csrf-token',\n csrf: 'double-submit' as const,\n exposeTokens: false,\n refreshFromCookie: true,\n};\n\n/** Percorsi pubblici che non richiedono il token CSRF (non hanno ancora una sessione). */\nconst CSRF_EXEMPT_PATHS = [\n '/api/accessi/auth/login',\n '/api/accessi/auth/refresh',\n '/api/accessi/auth/confirm-reset-password',\n '/api/accessi/auth/two-factor/verify',\n '/api/accessi/auth/two-factor/resend',\n '/api/accessi/auth/bootstrap-admin',\n '/api/accessi/email/',\n '/api/accessi/federated-auth/exchange',\n '/api/accessi/user/register',\n];\n\nconst UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\n/** Risolve la configurazione dei cookie; `undefined` quando la modalita e disattivata. */\nexport function resolveAccessiAuthCookieOptions(\n options: Pick<AccessiOptions, 'authCookie'>,\n): ResolvedAccessiAuthCookieOptions | undefined {\n const raw = options.authCookie;\n if (!raw || raw.enabled === false) return undefined;\n\n return {\n secure: raw.secure !== false,\n sameSite: raw.sameSite ?? DEFAULTS.sameSite,\n ...(raw.domain ? { domain: raw.domain } : {}),\n accessTokenName: raw.accessTokenName ?? DEFAULTS.accessTokenName,\n refreshTokenName: raw.refreshTokenName ?? DEFAULTS.refreshTokenName,\n csrfTokenName: raw.csrfTokenName ?? DEFAULTS.csrfTokenName,\n accessPath: raw.accessPath ?? DEFAULTS.accessPath,\n refreshPath: raw.refreshPath ?? DEFAULTS.refreshPath,\n csrfPath: raw.csrfPath ?? DEFAULTS.csrfPath,\n csrfHeaderName: (raw.csrfHeaderName ?? DEFAULTS.csrfHeaderName).toLowerCase(),\n csrf: raw.csrf ?? DEFAULTS.csrf,\n exposeTokens: raw.exposeTokens === true,\n refreshFromCookie: raw.refreshFromCookie !== false,\n };\n}\n\n/** Legge i cookie senza aggiungere la dipendenza `cookie-parser`. */\nexport function parseAccessiCookieHeader(header: string | undefined): Record<string, string> {\n const cookies: Record<string, string> = {};\n if (!header) return cookies;\n for (const part of header.split(';')) {\n const separator = part.indexOf('=');\n if (separator < 0) continue;\n const name = part.slice(0, separator).trim();\n if (!name) continue;\n const rawValue = part.slice(separator + 1).trim();\n try {\n cookies[name] = decodeURIComponent(rawValue);\n } catch {\n cookies[name] = rawValue;\n }\n }\n return cookies;\n}\n\n/** True per richieste che modificano stato (dove serve il CSRF). */\nexport function isAccessiUnsafeMethod(method: string): boolean {\n return UNSAFE_METHODS.has(method.toUpperCase());\n}\n\n/** True per gli endpoint pubblici esenti da CSRF. */\nexport function isAccessiCsrfExemptPath(path: string): boolean {\n return CSRF_EXEMPT_PATHS.some((exempt) =>\n exempt.endsWith('/') ? path.startsWith(exempt) : path === exempt,\n );\n}\n\nfunction tokenMaxAgeSeconds(token: string | undefined): number | undefined {\n if (!token) return undefined;\n const decoded = decodeJwt(token) as jwt.JwtPayload | string | null;\n if (!decoded || typeof decoded === 'string') return undefined;\n const exp = Number(decoded.exp);\n if (!Number.isFinite(exp)) return undefined;\n return Math.max(0, Math.floor(exp - Date.now() / 1000));\n}\n\nfunction serializeCookie(\n name: string,\n value: string,\n options: {\n path: string;\n maxAgeSeconds?: number;\n httpOnly?: boolean;\n secure: boolean;\n sameSite: 'strict' | 'lax' | 'none';\n domain?: string;\n },\n): string {\n const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`];\n if (options.domain) parts.push(`Domain=${options.domain}`);\n if (options.maxAgeSeconds !== undefined) parts.push(`Max-Age=${options.maxAgeSeconds}`);\n if (options.httpOnly) parts.push('HttpOnly');\n if (options.secure) parts.push('Secure');\n const sameSite = { strict: 'Strict', lax: 'Lax', none: 'None' }[options.sameSite];\n parts.push(`SameSite=${sameSite}`);\n return parts.join('; ');\n}\n\nfunction appendCookie(res: Pick<Response, 'append'>, cookie: string): void {\n res.append('Set-Cookie', cookie);\n}\n\n/** Imposta i cookie access, refresh e (se assente) CSRF. */\nexport function setAccessiAuthCookies(\n res: Pick<Response, 'append'>,\n config: ResolvedAccessiAuthCookieOptions,\n tokens: AccessiAuthTokenPair,\n): void {\n if (tokens.access) {\n appendCookie(res, serializeCookie(config.accessTokenName, tokens.access, {\n path: config.accessPath,\n ...(tokenMaxAgeSeconds(tokens.access) !== undefined\n ? { maxAgeSeconds: tokenMaxAgeSeconds(tokens.access) }\n : {}),\n httpOnly: true,\n secure: config.secure,\n sameSite: config.sameSite,\n ...(config.domain ? { domain: config.domain } : {}),\n }));\n }\n if (tokens.refresh) {\n appendCookie(res, serializeCookie(config.refreshTokenName, tokens.refresh, {\n path: config.refreshPath,\n ...(tokenMaxAgeSeconds(tokens.refresh) !== undefined\n ? { maxAgeSeconds: tokenMaxAgeSeconds(tokens.refresh) }\n : {}),\n httpOnly: true,\n secure: config.secure,\n sameSite: config.sameSite,\n ...(config.domain ? { domain: config.domain } : {}),\n }));\n }\n}\n\n/** Cancella i cookie di sessione (logout/revoca). */\nexport function clearAccessiAuthCookies(\n res: Pick<Response, 'append'>,\n config: ResolvedAccessiAuthCookieOptions,\n): void {\n for (const [name, path] of [\n [config.accessTokenName, config.accessPath],\n [config.refreshTokenName, config.refreshPath],\n [config.csrfTokenName, config.csrfPath],\n ] as const) {\n appendCookie(res, serializeCookie(name, '', {\n path,\n maxAgeSeconds: 0,\n httpOnly: name !== config.csrfTokenName,\n secure: config.secure,\n sameSite: config.sameSite,\n ...(config.domain ? { domain: config.domain } : {}),\n }));\n }\n}\n\nexport interface AccessiAuthTokenValue {\n value?: string;\n}\n\n/** Forma comune dei risultati di auth: stringa o `TokenResult` di Accessi. */\nexport interface AccessiAuthResultLike {\n token?: string | AccessiAuthTokenValue;\n refreshToken?: string | AccessiAuthTokenValue;\n}\n\nfunction accessiTokenValue(token: string | AccessiAuthTokenValue | undefined): string | undefined {\n if (typeof token === 'string') return token === '' ? undefined : token;\n return token?.value;\n}\n\n/**\n * Prepara la risposta di login/refresh: imposta i cookie e rimuove i token dal\n * body quando la modalita cookie non prevede `exposeTokens`.\n */\nexport function applyAccessiAuthCookies<T extends AccessiAuthResultLike>(\n res: Pick<Response, 'append'>,\n config: ResolvedAccessiAuthCookieOptions | undefined,\n result: T,\n): T {\n if (!config) return result;\n setAccessiAuthCookies(res, config, {\n access: accessiTokenValue(result.token),\n refresh: accessiTokenValue(result.refreshToken),\n });\n hideAccessiLoginTokens(config, result);\n return result;\n}\n\n/** Rimuove i token dal `LoginResult` quando la modalita cookie li nasconde. */\nexport function hideAccessiLoginTokens(\n config: ResolvedAccessiAuthCookieOptions | undefined,\n result: { token?: unknown; refreshToken?: unknown },\n): void {\n if (!config || config.exposeTokens) return;\n delete result.token;\n delete result.refreshToken;\n}\n\n/** Legge l'access token dal cookie (per test e per host senza middleware). */\nexport function getAccessiAccessTokenFromCookie(\n header: string | undefined,\n config: ResolvedAccessiAuthCookieOptions,\n): string | undefined {\n return parseAccessiCookieHeader(header)[config.accessTokenName];\n}\n\n/** Legge il refresh token dal cookie. */\nexport function getAccessiRefreshTokenFromCookie(\n header: string | undefined,\n config: ResolvedAccessiAuthCookieOptions,\n): string | undefined {\n return parseAccessiCookieHeader(header)[config.refreshTokenName];\n}\n\nfunction safeEqual(left: string, right: string): boolean {\n const a = Buffer.from(left);\n const b = Buffer.from(right);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction csrfError(res: Response): void {\n res.status(403).json({\n severity: 'error',\n status: 403,\n statusCode: 2,\n code: 'AUTH_CSRF_INVALID',\n error: 'AUTH_CSRF_INVALID',\n message: 'Token CSRF mancante o non valido.',\n });\n}\n\n/**\n * Middleware della modalita cookie.\n *\n * - copia l'access token dal cookie nell'header `Authorization`, cosi guard,\n * middleware e controller esistenti funzionano senza modifiche;\n * - garantisce un cookie CSRF double-submit leggibile dal client;\n * - blocca le richieste autenticate via cookie che modificano stato senza\n * l'header CSRF, salvo endpoint pubblici di bootstrap della sessione.\n */\nexport function createAccessiAuthCookieMiddleware(\n options: Pick<AccessiOptions, 'authCookie'>,\n isAccessiRoute: (path: string) => boolean,\n): ((req: Request, res: Response, next: NextFunction) => void) | undefined {\n const config = resolveAccessiAuthCookieOptions(options);\n if (!config) return undefined;\n\n return (req: Request, res: Response, next: NextFunction): void => {\n if (!isAccessiRoute(req.path)) {\n next();\n return;\n }\n\n const cookies = parseAccessiCookieHeader(req.headers.cookie);\n let csrfToken = cookies[config.csrfTokenName];\n if (!csrfToken && config.csrf === 'double-submit') {\n csrfToken = randomBytes(32).toString('base64url');\n appendCookie(res, serializeCookie(config.csrfTokenName, csrfToken, {\n path: config.csrfPath,\n httpOnly: false,\n secure: config.secure,\n sameSite: config.sameSite,\n ...(config.domain ? { domain: config.domain } : {}),\n }));\n }\n if (config.csrf === 'double-submit' && csrfToken) {\n // Rende il token leggibile anche a una SPA su altra origine (via CORS,\n // con `Access-Control-Expose-Headers: X-CSRF-Token`).\n res.setHeader('X-CSRF-Token', csrfToken);\n }\n\n const accessToken = cookies[config.accessTokenName];\n const hasAuthorization = typeof req.headers.authorization === 'string'\n && req.headers.authorization.trim() !== '';\n if (accessToken && !hasAuthorization) {\n req.headers.authorization = `Bearer ${accessToken}`;\n\n if (\n config.csrf === 'double-submit'\n && isAccessiUnsafeMethod(req.method)\n && !isAccessiCsrfExemptPath(req.path)\n ) {\n const headerValue = req.headers[config.csrfHeaderName];\n const provided = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n if (!csrfToken || !provided || !safeEqual(provided, csrfToken)) {\n csrfError(res);\n return;\n }\n }\n }\n\n next();\n };\n}\n\n/** True se il nome cookie e valido per l'header `Set-Cookie`. */\nexport function isValidAccessiCookieName(name: string): boolean {\n return COOKIE_NAME.test(name);\n}\n\n/** Helpers per le combinazioni di cookie supportate (usati dalla validazione). */\nexport function accessiCookieNames(config: ResolvedAccessiAuthCookieOptions): string[] {\n return [config.accessTokenName, config.refreshTokenName, config.csrfTokenName];\n}\n"]}