emilsoftware-utilities 2.0.0-dev.67 → 2.0.0-dev.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessi/resource-server/errors.d.ts +1 -1
- package/dist/accessi/resource-server/errors.js.map +1 -1
- package/dist/accessi/resource-server/express.js +21 -0
- package/dist/accessi/resource-server/express.js.map +1 -1
- package/dist/accessi/resource-server/nest.js +13 -0
- package/dist/accessi/resource-server/nest.js.map +1 -1
- package/dist/accessi/resource-server/runtime.js +11 -1
- package/dist/accessi/resource-server/runtime.js.map +1 -1
- package/dist/accessi/resource-server/types.d.ts +7 -0
- package/dist/accessi/resource-server/types.js.map +1 -1
- package/dist/accessi/server/index.d.ts +1 -0
- package/dist/accessi/server/index.js +1 -0
- package/dist/accessi/server/index.js.map +1 -1
- package/dist/accessi/server/standalone.d.ts +41 -0
- package/dist/accessi/server/standalone.js +264 -0
- package/dist/accessi/server/standalone.js.map +1 -0
- package/dist/accessi-module/AccessiModule.d.ts +53 -2
- package/dist/accessi-module/AccessiModule.js +5 -2
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/accessiFetch.d.ts +5 -0
- package/dist/accessi-module/Console/accessiFetch.js +7 -4
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
- package/dist/accessi-module/Console/console.js +21 -7
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.d.ts +31 -1
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js +28 -3
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.d.ts +15 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +6 -0
- package/dist/accessi-module/Console/generated/model/index.js +6 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/loginResult.d.ts +2 -0
- package/dist/accessi-module/Console/generated/model/loginResult.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.js.map +1 -0
- package/dist/accessi-module/Console/wiki.js +16 -3
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.d.ts +6 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.js +24 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.js.map +1 -1
- package/dist/accessi-module/Controllers/AuthController.d.ts +3 -1
- package/dist/accessi-module/Controllers/AuthController.js +90 -8
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Controllers/ConsoleEntryController.d.ts +2 -0
- package/dist/accessi-module/Controllers/ConsoleEntryController.js +11 -3
- package/dist/accessi-module/Controllers/ConsoleEntryController.js.map +1 -1
- package/dist/accessi-module/Controllers/EmailController.js +1 -1
- package/dist/accessi-module/Controllers/EmailController.js.map +1 -1
- package/dist/accessi-module/Controllers/UserController.js +1 -1
- package/dist/accessi-module/Controllers/UserController.js.map +1 -1
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.d.ts +21 -0
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.js +74 -0
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/LoginResponse.d.ts +1 -0
- package/dist/accessi-module/Dtos/LoginResponse.js +6 -0
- package/dist/accessi-module/Dtos/LoginResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/RefreshTokenDtos.d.ts +12 -0
- package/dist/accessi-module/Dtos/RefreshTokenDtos.js +50 -0
- package/dist/accessi-module/Dtos/RefreshTokenDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +2 -0
- package/dist/accessi-module/Dtos/index.js +2 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/AuthService/AuthService.d.ts +14 -0
- package/dist/accessi-module/Services/AuthService/AuthService.js +99 -6
- package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js +8 -16
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js.map +1 -1
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.d.ts +15 -0
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.js +85 -0
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.js.map +1 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.js +7 -1
- package/dist/accessi-module/federated-auth/FederatedAuthService.js.map +1 -1
- package/dist/accessi-module/index.d.ts +17 -1
- package/dist/accessi-module/index.js +71 -5
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/jwt/jwt.strategy.js +4 -0
- package/dist/accessi-module/jwt/jwt.strategy.js.map +1 -1
- package/dist/accessi-module/middleware/authenticateGen.js +4 -0
- package/dist/accessi-module/middleware/authenticateGen.js.map +1 -1
- package/dist/accessi-module/security/audit.d.ts +7 -0
- package/dist/accessi-module/security/audit.js +14 -0
- package/dist/accessi-module/security/audit.js.map +1 -0
- package/dist/accessi-module/security/authenticatedToken.d.ts +1 -1
- package/dist/accessi-module/security/authenticatedToken.js +3 -3
- package/dist/accessi-module/security/authenticatedToken.js.map +1 -1
- package/dist/accessi-module/security/consoleEntry.d.ts +58 -11
- package/dist/accessi-module/security/consoleEntry.js +181 -31
- package/dist/accessi-module/security/consoleEntry.js.map +1 -1
- package/dist/accessi-module/security/edgeRateLimit.d.ts +33 -0
- package/dist/accessi-module/security/edgeRateLimit.js +81 -0
- package/dist/accessi-module/security/edgeRateLimit.js.map +1 -0
- package/dist/accessi-module/security/jwks.d.ts +33 -0
- package/dist/accessi-module/security/jwks.js +83 -0
- package/dist/accessi-module/security/jwks.js.map +1 -0
- package/dist/accessi-module/security/jwksBootstrap.d.ts +15 -0
- package/dist/accessi-module/security/jwksBootstrap.js +44 -0
- package/dist/accessi-module/security/jwksBootstrap.js.map +1 -0
- package/dist/accessi-module/security/jwtTokenOptions.d.ts +9 -2
- package/dist/accessi-module/security/jwtTokenOptions.js +18 -4
- package/dist/accessi-module/security/jwtTokenOptions.js.map +1 -1
- package/dist/accessi-module/security/passwordResetToken.d.ts +1 -1
- package/dist/accessi-module/security/passwordResetToken.js.map +1 -1
- package/dist/accessi-module/security/publicAuthRateLimit.d.ts +9 -7
- package/dist/accessi-module/security/publicAuthRateLimit.js +55 -78
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/security/rateLimitStore.d.ts +34 -0
- package/dist/accessi-module/security/rateLimitStore.js +145 -0
- package/dist/accessi-module/security/rateLimitStore.js.map +1 -0
- package/dist/accessi-module/security/refreshTokenRotation.d.ts +40 -0
- package/dist/accessi-module/security/refreshTokenRotation.js +91 -0
- package/dist/accessi-module/security/refreshTokenRotation.js.map +1 -0
- package/dist/accessi-module/security/serviceTokenGuard.d.ts +3 -1
- package/dist/accessi-module/security/serviceTokenGuard.js +11 -6
- package/dist/accessi-module/security/serviceTokenGuard.js.map +1 -1
- package/dist/accessi-module/security/serviceTokenRateLimit.d.ts +5 -4
- package/dist/accessi-module/security/serviceTokenRateLimit.js +33 -29
- package/dist/accessi-module/security/serviceTokenRateLimit.js.map +1 -1
- package/dist/accessi-module/security/sessionRevocation.d.ts +52 -0
- package/dist/accessi-module/security/sessionRevocation.js +124 -0
- package/dist/accessi-module/security/sessionRevocation.js.map +1 -0
- package/dist/accessi-module/security/validateOptions.d.ts +19 -0
- package/dist/accessi-module/security/validateOptions.js +115 -0
- package/dist/accessi-module/security/validateOptions.js.map +1 -0
- package/dist/emilsoftware-utilities-2.0.0-dev.69.tgz +0 -0
- package/dist/initEmilsoftwareModule.js +39 -3
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/dist/scripts/startAccessiService.d.ts +1 -0
- package/dist/scripts/startAccessiService.js +11 -0
- package/dist/scripts/startAccessiService.js.map +1 -0
- package/docs/accessi-openapi-fingerprint.json +190 -0
- package/docs/gateway-rate-limit.md +98 -0
- package/docs/standalone-service.md +176 -0
- package/integration-prompt.md +299 -8
- package/package.json +11 -5
- package/dist/emilsoftware-utilities-2.0.0-dev.67.tgz +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standalone.js","sourceRoot":"","sources":["../../../src/accessi/server/standalone.ts"],"names":[],"mappings":"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","sourcesContent":["import express from 'express';\nimport type { Application, Request, Response } from 'express';\nimport type { Server } from 'http';\nimport { Logger } from '../../Logger';\nimport { Orm } from '../../Orm';\nimport { initializeAccessiModule } from '../../accessi-module';\nimport type {\n AccessiModuleInitializationResult,\n} from '../../accessi-module';\nimport type { AccessiOptions } from '../../accessi-module/AccessiModule';\nimport { createAccessiOptionsFromEnv } from '../../accessi-module/database-updates/accessiOptionsFromEnv';\nimport {\n ACCESSI_SCHEMA_VERSION,\n} from '../../accessi-module/database-updates/accessiSchema';\nimport { AccessiDatabaseUpdater } from '../../accessi-module/database-updates/AccessiDatabaseUpdater';\nimport { assertValidAccessiOptions, validateAccessiOptions } from '../../accessi-module/security/validateOptions';\n\nexport interface AccessiReadinessCheck {\n name: string;\n check: () => boolean | Promise<boolean>;\n}\n\nexport interface AccessiServiceOptions {\n /** Applicazione Express gia esistente. Default: nuova app. */\n app?: Application;\n /** Configurazione completa. Default: `createAccessiOptionsFromEnv()`. */\n accessiOptions?: AccessiOptions;\n port?: number;\n host?: string;\n /** Path base degli endpoint health. Default: `/health`. */\n healthPath?: string;\n /** Espone `/health/metrics` in formato Prometheus. Default: true. */\n metrics?: boolean;\n /** Check aggiuntivi per la readiness. */\n readinessChecks?: AccessiReadinessCheck[];\n /** Timeout chiusura server. Default: 10000 ms. */\n shutdownTimeoutMs?: number;\n}\n\nexport interface AccessiService {\n app: Application;\n nestApp: AccessiModuleInitializationResult['nestApp'];\n document: AccessiModuleInitializationResult['document'];\n start(): Promise<Server>;\n stop(): Promise<void>;\n}\n\ninterface HealthCheckResult {\n ok: boolean;\n detail?: string;\n}\n\nfunction normalizePath(value: string): string {\n return `/${value.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\nfunction createMetrics() {\n const startedAt = Date.now();\n let requests = 0;\n let inFlight = 0;\n const statuses = new Map<string, number>();\n\n const middleware = (_req: Request, res: Response, next: () => void): void => {\n requests += 1;\n inFlight += 1;\n res.on('finish', () => {\n inFlight = Math.max(0, inFlight - 1);\n const status = String(res.statusCode);\n statuses.set(status, (statuses.get(status) ?? 0) + 1);\n });\n next();\n };\n\n const render = (): string => {\n const memory = process.memoryUsage();\n const lines = [\n '# HELP accessi_http_requests_total Richieste HTTP totali.',\n '# TYPE accessi_http_requests_total counter',\n ...[...statuses.entries()].map(\n ([status, count]) => `accessi_http_requests_total{status=\"${status}\"} ${count}`,\n ),\n '# HELP accessi_http_in_flight Richieste HTTP in corso.',\n '# TYPE accessi_http_in_flight gauge',\n `accessi_http_in_flight ${inFlight}`,\n '# HELP accessi_process_uptime_seconds Uptime del processo.',\n '# TYPE accessi_process_uptime_seconds gauge',\n `accessi_process_uptime_seconds ${Math.floor((Date.now() - startedAt) / 1000)}`,\n '# HELP accessi_process_memory_bytes Memoria del processo.',\n '# TYPE accessi_process_memory_bytes gauge',\n `accessi_process_memory_bytes{type=\"rss\"} ${memory.rss}`,\n `accessi_process_memory_bytes{type=\"heapUsed\"} ${memory.heapUsed}`,\n `accessi_process_memory_bytes{type=\"heapTotal\"} ${memory.heapTotal}`,\n '# HELP accessi_http_requests_started_total Richieste HTTP avviate.',\n '# TYPE accessi_http_requests_started_total counter',\n `accessi_http_requests_started_total ${requests}`,\n ];\n return `${lines.join('\\n')}\\n`;\n };\n\n return { middleware, render };\n}\n\nfunction collectHealthStores(options: AccessiOptions): Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> {\n const stores: Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> = [];\n const seen = new Set<unknown>();\n\n const add = (name: string, store: { healthCheck?: () => Promise<boolean> } | undefined): void => {\n if (!store || seen.has(store) || typeof store.healthCheck !== 'function') return;\n seen.add(store);\n stores.push({ name, store });\n };\n\n add('publicAuthRateLimit', options.publicAuthRateLimit?.store);\n add('serviceTokenRateLimit', options.serviceTokens?.rateLimitStore);\n add('consoleEntry', options.consoleEntry?.store);\n add('edgeRateLimit', options.edgeRateLimit?.store);\n add('sessionRevocation', options.sessionRevocation?.store);\n add('refreshTokenRotation', options.refreshTokenRotation?.store);\n return stores;\n}\n\nasync function checkDatabase(options: AccessiOptions): Promise<HealthCheckResult> {\n try {\n const version = await AccessiDatabaseUpdater.getCurrentVersion(options);\n if (!version) {\n return { ok: false, detail: 'schema Accessi non inizializzato' };\n }\n return {\n ok: true,\n detail: version === ACCESSI_SCHEMA_VERSION\n ? version\n : `${version} (atteso ${ACCESSI_SCHEMA_VERSION})`,\n };\n } catch (error) {\n return { ok: false, detail: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/**\n * Crea un servizio Accessi standalone con health, readiness, metriche e shutdown.\n *\n * Non apre la porta finche non viene chiamato `start()`.\n */\nexport async function createAccessiService(\n options: AccessiServiceOptions = {},\n): Promise<AccessiService> {\n const logger = new Logger('AccessiService');\n const accessiOptions = options.accessiOptions ?? createAccessiOptionsFromEnv();\n assertValidAccessiOptions(accessiOptions);\n for (const warning of validateAccessiOptions(accessiOptions).warnings) {\n logger.warning(`Configurazione Accessi: ${warning.code} - ${warning.message}`);\n }\n\n const app = options.app ?? express();\n const healthPath = normalizePath(options.healthPath ?? '/health');\n const metrics = createMetrics();\n const readinessChecks = options.readinessChecks ?? [];\n let initialized = false;\n let nestApp: AccessiModuleInitializationResult['nestApp'] | undefined;\n let document: AccessiModuleInitializationResult['document'] | undefined;\n let server: Server | undefined;\n let stopping = false;\n\n app.use(metrics.middleware);\n\n app.get(`${healthPath}/live`, (_req: Request, res: Response) => {\n res.status(200).json({\n status: 'ok',\n uptimeSeconds: Math.floor(process.uptime()),\n });\n });\n\n app.get(`${healthPath}/ready`, async (_req: Request, res: Response) => {\n if (!initialized || !nestApp) {\n res.status(503).json({\n status: 'error',\n checks: { bootstrap: { ok: false, detail: 'bootstrap non completato' } },\n });\n return;\n }\n\n const checks: Record<string, HealthCheckResult> = {\n bootstrap: { ok: true },\n database: await checkDatabase(accessiOptions),\n };\n\n const stores = collectHealthStores(accessiOptions);\n await Promise.all(stores.map(async ({ name, store }) => {\n try {\n checks[name] = { ok: Boolean(await store.healthCheck?.()) };\n } catch (error) {\n checks[name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }));\n\n for (const check of readinessChecks) {\n try {\n const ok = await check.check();\n checks[check.name] = { ok: Boolean(ok) };\n } catch (error) {\n checks[check.name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n const ok = Object.values(checks).every((check) => check.ok);\n res.status(ok ? 200 : 503).json({\n status: ok ? 'ok' : 'error',\n checks,\n timestamp: new Date().toISOString(),\n });\n });\n\n if (options.metrics !== false) {\n app.get(`${healthPath}/metrics`, (_req: Request, res: Response) => {\n res.setHeader('Content-Type', 'text/plain; version=0.0.4');\n res.status(200).send(metrics.render());\n });\n }\n\n const result = await initializeAccessiModule(app, accessiOptions);\n nestApp = result.nestApp;\n document = result.document;\n initialized = true;\n\n const stop = async (): Promise<void> => {\n if (stopping) return;\n stopping = true;\n const timeout = Math.max(1_000, options.shutdownTimeoutMs ?? 10_000);\n await Promise.race([\n new Promise<void>((resolve) => {\n if (!server) return resolve();\n server.close(() => resolve());\n }),\n new Promise<void>((resolve) => setTimeout(resolve, timeout)),\n ]);\n try {\n await nestApp?.close();\n } finally {\n await Orm.closePools();\n }\n };\n\n const start = async (): Promise<Server> => {\n if (server) return server;\n const port = options.port ?? Number(process.env.PORT ?? 3000);\n server = await new Promise<Server>((resolve, reject) => {\n const listener = options.host\n ? app.listen(port, options.host, () => resolve(listener))\n : app.listen(port, () => resolve(listener));\n listener.once('error', reject);\n });\n const address = server.address();\n const actualPort = typeof address === 'object' && address ? address.port : port;\n logger.info(`Accessi Service in ascolto su http://${options.host ?? '0.0.0.0'}:${actualPort}`);\n return server;\n };\n\n return {\n app,\n get nestApp() {\n if (!nestApp) throw new Error('Accessi Service non inizializzato.');\n return nestApp;\n },\n get document() {\n if (!document) throw new Error('Documento OpenAPI non disponibile.');\n return document;\n },\n start,\n stop,\n };\n}\n\n/**\n * Avvia Accessi Service e registra SIGTERM/SIGINT per lo shutdown graceful.\n */\nexport async function startAccessiService(options: AccessiServiceOptions = {}): Promise<AccessiService> {\n const service = await createAccessiService(options);\n await service.start();\n\n let shuttingDown = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n new Logger('AccessiService').info(`Ricevuto ${signal}: arresto in corso.`);\n await service.stop();\n };\n\n process.once('SIGTERM', () => { void shutdown('SIGTERM'); });\n process.once('SIGINT', () => { void shutdown('SIGINT'); });\n return service;\n}\n"]}
|
|
@@ -6,9 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Options } from 'node-firebird';
|
|
8
8
|
import { DynamicModule } from '@nestjs/common';
|
|
9
|
-
import type { LoggerService } from '@nestjs/common';
|
|
9
|
+
import type { INestApplication, LoggerService } from '@nestjs/common';
|
|
10
10
|
import type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';
|
|
11
11
|
import type { AccessiAccessTokenAlgorithm } from './security/jwtTokenOptions';
|
|
12
|
+
import type { ConsoleEntryStore } from './security/consoleEntry';
|
|
13
|
+
import type { RateLimitStore } from './security/rateLimitStore';
|
|
14
|
+
import type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';
|
|
15
|
+
import type { SessionRevocationOptions } from './security/sessionRevocation';
|
|
16
|
+
import type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';
|
|
12
17
|
/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */
|
|
13
18
|
export interface JwtOptions {
|
|
14
19
|
/** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */
|
|
@@ -25,8 +30,37 @@ export interface JwtOptions {
|
|
|
25
30
|
publicKey?: string;
|
|
26
31
|
/** Key id pubblicato nella JWKS, per rotazione chiavi. */
|
|
27
32
|
keyId?: string;
|
|
33
|
+
/** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */
|
|
34
|
+
jwksPath?: string;
|
|
35
|
+
/** Chiavi pubbliche precedenti, esposte in JWKS durante la rotazione. */
|
|
36
|
+
previousPublicKeys?: Array<{
|
|
37
|
+
publicKey: string;
|
|
38
|
+
keyId: string;
|
|
39
|
+
algorithm?: AccessiAccessTokenAlgorithm;
|
|
40
|
+
}>;
|
|
28
41
|
/** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */
|
|
29
42
|
expiresIn: string;
|
|
43
|
+
/**
|
|
44
|
+
* Durata del refresh token. Se assente il refresh token non viene emesso.
|
|
45
|
+
* Consigliato: `30d`.
|
|
46
|
+
*/
|
|
47
|
+
refreshExpiresIn?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Configurazione dei ticket di ingresso alla console. */
|
|
50
|
+
export interface ConsoleEntryOptions {
|
|
51
|
+
/** Durata del ticket in millisecondi. Default 60000. */
|
|
52
|
+
ttlMs?: number;
|
|
53
|
+
/** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */
|
|
54
|
+
store?: ConsoleEntryStore;
|
|
55
|
+
}
|
|
56
|
+
/** Impostazioni HTTP del servizio Accessi. */
|
|
57
|
+
export interface AccessiHttpOptions {
|
|
58
|
+
/** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */
|
|
59
|
+
cors?: Parameters<INestApplication['enableCors']>[0] | false;
|
|
60
|
+
/** Trust proxy per IP reali dietro load balancer/reverse proxy. */
|
|
61
|
+
trustProxy?: boolean | number | string;
|
|
62
|
+
/** Header di sicurezza di base su console/OpenAPI. Default: true. */
|
|
63
|
+
securityHeaders?: boolean;
|
|
30
64
|
}
|
|
31
65
|
/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */
|
|
32
66
|
export interface EmailOptions {
|
|
@@ -61,13 +95,16 @@ export interface PublicAuthRateLimitRuleOptions {
|
|
|
61
95
|
windowMs: number;
|
|
62
96
|
maxAttempts: number;
|
|
63
97
|
}
|
|
64
|
-
/** Protezione
|
|
98
|
+
/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */
|
|
65
99
|
export interface PublicAuthRateLimitOptions {
|
|
66
100
|
enabled?: boolean;
|
|
101
|
+
/** Store condiviso (es. Redis). Default: memoria del processo. */
|
|
102
|
+
store?: RateLimitStore;
|
|
67
103
|
login?: PublicAuthRateLimitRuleOptions;
|
|
68
104
|
register?: PublicAuthRateLimitRuleOptions;
|
|
69
105
|
passwordResetEmail?: PublicAuthRateLimitRuleOptions;
|
|
70
106
|
passwordResetConfirm?: PublicAuthRateLimitRuleOptions;
|
|
107
|
+
refresh?: PublicAuthRateLimitRuleOptions;
|
|
71
108
|
getUserByToken?: PublicAuthRateLimitRuleOptions;
|
|
72
109
|
twoFactorVerify?: PublicAuthRateLimitRuleOptions;
|
|
73
110
|
twoFactorResend?: PublicAuthRateLimitRuleOptions;
|
|
@@ -96,6 +133,8 @@ export interface ServiceTokenOptions {
|
|
|
96
133
|
enabled?: boolean;
|
|
97
134
|
/** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */
|
|
98
135
|
defaultTtlDays?: number;
|
|
136
|
+
/** Store condiviso per il rate limit dei service token. Default: memoria. */
|
|
137
|
+
rateLimitStore?: RateLimitStore;
|
|
99
138
|
}
|
|
100
139
|
/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */
|
|
101
140
|
export type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';
|
|
@@ -195,6 +234,8 @@ export interface AccessiOptions {
|
|
|
195
234
|
adminBootstrap?: AdminBootstrapOptions;
|
|
196
235
|
/** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */
|
|
197
236
|
publicBaseUrl?: string;
|
|
237
|
+
/** Base URL API per la console quando UI e API sono su domini diversi. */
|
|
238
|
+
consoleApiBaseUrl?: string;
|
|
198
239
|
/**
|
|
199
240
|
* Documentazione OpenAPI del modulo. Default invariati:
|
|
200
241
|
* UI `accessi/openapi`, JSON `accessi/openapi.json`.
|
|
@@ -204,6 +245,16 @@ export interface AccessiOptions {
|
|
|
204
245
|
logger?: LoggerService;
|
|
205
246
|
/** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */
|
|
206
247
|
bufferLogs?: boolean;
|
|
248
|
+
/** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */
|
|
249
|
+
consoleEntry?: ConsoleEntryOptions;
|
|
250
|
+
/** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */
|
|
251
|
+
edgeRateLimit?: AccessiEdgeRateLimitOptions;
|
|
252
|
+
/** CORS, trust proxy e header di sicurezza del servizio. */
|
|
253
|
+
http?: AccessiHttpOptions;
|
|
254
|
+
/** Revoca sessioni per utente tramite store memory/Redis. */
|
|
255
|
+
sessionRevocation?: SessionRevocationOptions;
|
|
256
|
+
/** Refresh token monouso tramite rotazione memory/Redis. */
|
|
257
|
+
refreshTokenRotation?: RefreshTokenRotationOptions;
|
|
207
258
|
}
|
|
208
259
|
export declare class AccessiModule {
|
|
209
260
|
/**
|
|
@@ -27,6 +27,7 @@ const authenticateGen_1 = require("./middleware/authenticateGen");
|
|
|
27
27
|
const AccessiDatabaseUpdater_1 = require("./database-updates/AccessiDatabaseUpdater");
|
|
28
28
|
const FederatedAuthService_1 = require("./federated-auth/FederatedAuthService");
|
|
29
29
|
const FederatedAuthController_1 = require("./federated-auth/FederatedAuthController");
|
|
30
|
+
const FederatedAuthExchangeController_1 = require("./federated-auth/FederatedAuthExchangeController");
|
|
30
31
|
const AccessiConsoleController_1 = require("./Controllers/AccessiConsoleController");
|
|
31
32
|
const ConsoleEntryController_1 = require("./Controllers/ConsoleEntryController");
|
|
32
33
|
const ServiceTokenController_1 = require("./Controllers/ServiceTokenController");
|
|
@@ -36,6 +37,7 @@ const SchemaController_1 = require("./Controllers/SchemaController");
|
|
|
36
37
|
const AccessiIntrospectionController_1 = require("./Controllers/AccessiIntrospectionController");
|
|
37
38
|
const SchemaExportService_1 = require("./Services/SchemaExportService/SchemaExportService");
|
|
38
39
|
const AdminBootstrapService_1 = require("./Services/AdminBootstrapService/AdminBootstrapService");
|
|
40
|
+
const jwksBootstrap_1 = require("./security/jwksBootstrap");
|
|
39
41
|
const emailConfiguration_1 = require("./security/emailConfiguration");
|
|
40
42
|
let AccessiModule = AccessiModule_1 = class AccessiModule {
|
|
41
43
|
/**
|
|
@@ -67,7 +69,7 @@ let AccessiModule = AccessiModule_1 = class AccessiModule {
|
|
|
67
69
|
AccessiDatabaseUpdater_1.AccessiDatabaseUpdater,
|
|
68
70
|
FederatedAuthService_1.FederatedAuthService,
|
|
69
71
|
ServiceTokenService_1.ServiceTokenService,
|
|
70
|
-
serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService
|
|
72
|
+
serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService, jwksBootstrap_1.AccessiJwksBootstrapService
|
|
71
73
|
],
|
|
72
74
|
exports: [
|
|
73
75
|
'ACCESSI_OPTIONS',
|
|
@@ -100,11 +102,12 @@ exports.AccessiModule = AccessiModule = AccessiModule_1 = __decorate([
|
|
|
100
102
|
FederatedAuthController_1.FederatedAuthController,
|
|
101
103
|
AccessiConsoleController_1.AccessiConsoleController,
|
|
102
104
|
ConsoleEntryController_1.ConsoleEntryController,
|
|
105
|
+
FederatedAuthExchangeController_1.FederatedAuthExchangeController,
|
|
103
106
|
ServiceTokenController_1.ServiceTokenController,
|
|
104
107
|
SchemaController_1.SchemaController,
|
|
105
108
|
AccessiIntrospectionController_1.AccessiIntrospectionController,
|
|
106
109
|
],
|
|
107
|
-
providers: [AuthService_1.AuthService, TwoFactorService_1.TwoFactorService, UserService_1.UserService, EmailService_1.EmailService, PermissionService_1.PermissionService, FiltriService_1.FiltriService, ConfiguratorService_1.ConfiguratorService, jwt_strategy_1.JwtSimpleGuard, authenticateGen_1.AuthenticateGenService, AccessiDatabaseUpdater_1.AccessiDatabaseUpdater, FederatedAuthService_1.FederatedAuthService, ServiceTokenService_1.ServiceTokenService, serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService],
|
|
110
|
+
providers: [AuthService_1.AuthService, TwoFactorService_1.TwoFactorService, UserService_1.UserService, EmailService_1.EmailService, PermissionService_1.PermissionService, FiltriService_1.FiltriService, ConfiguratorService_1.ConfiguratorService, jwt_strategy_1.JwtSimpleGuard, authenticateGen_1.AuthenticateGenService, AccessiDatabaseUpdater_1.AccessiDatabaseUpdater, FederatedAuthService_1.FederatedAuthService, ServiceTokenService_1.ServiceTokenService, serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService, jwksBootstrap_1.AccessiJwksBootstrapService],
|
|
108
111
|
exports: [AuthService_1.AuthService, UserService_1.UserService, EmailService_1.EmailService, PermissionService_1.PermissionService, FiltriService_1.FiltriService, ConfiguratorService_1.ConfiguratorService, jwt_strategy_1.JwtSimpleGuard, authenticateGen_1.AuthenticateGenService, FederatedAuthService_1.FederatedAuthService, ServiceTokenService_1.ServiceTokenService, serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService],
|
|
109
112
|
})
|
|
110
113
|
], AccessiModule);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAI/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,sEAAsE;AAsO/D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;YAChE,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AA9CY,sCAAa;wBAAb,aAAa;IAnBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;SAC/B;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;QACtS,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CA8CzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm } from './security/jwtTokenOptions';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { assertEmailConfigured } from './security/emailConfiguration';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione in-memory degli endpoint pubblici. In cluster aggiungere un limite anche al gateway. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAS/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,sGAAmG;AACnG,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,4DAAuE;AACvE,sEAAsE;AAuR/D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B;aAAC;YAC7F,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AA9CY,sCAAa;wBAAb,aAAa;IApBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,iEAA+B;YAC/B,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;SAC/B;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B,CAAC;QACnU,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CA8CzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { INestApplication, LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm } from './security/jwtTokenOptions';\nimport type { ConsoleEntryStore } from './security/consoleEntry';\nimport type { RateLimitStore } from './security/rateLimitStore';\nimport type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';\nimport type { SessionRevocationOptions } from './security/sessionRevocation';\nimport type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { FederatedAuthExchangeController } from './federated-auth/FederatedAuthExchangeController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { AccessiJwksBootstrapService } from './security/jwksBootstrap';\nimport { assertEmailConfigured } from './security/emailConfiguration';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */\n jwksPath?: string;\n /** Chiavi pubbliche precedenti, esposte in JWKS durante la rotazione. */\n previousPublicKeys?: Array<{\n publicKey: string;\n keyId: string;\n algorithm?: AccessiAccessTokenAlgorithm;\n }>;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n /**\n * Durata del refresh token. Se assente il refresh token non viene emesso.\n * Consigliato: `30d`.\n */\n refreshExpiresIn?: string;\n}\n\n/** Configurazione dei ticket di ingresso alla console. */\nexport interface ConsoleEntryOptions {\n /** Durata del ticket in millisecondi. Default 60000. */\n ttlMs?: number;\n /** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */\n store?: ConsoleEntryStore;\n}\n\n/** Impostazioni HTTP del servizio Accessi. */\nexport interface AccessiHttpOptions {\n /** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */\n cors?: Parameters<INestApplication['enableCors']>[0] | false;\n /** Trust proxy per IP reali dietro load balancer/reverse proxy. */\n trustProxy?: boolean | number | string;\n /** Header di sicurezza di base su console/OpenAPI. Default: true. */\n securityHeaders?: boolean;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n /** Store condiviso (es. Redis). Default: memoria del processo. */\n store?: RateLimitStore;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n refresh?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n /** Store condiviso per il rate limit dei service token. Default: memoria. */\n rateLimitStore?: RateLimitStore;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /** Base URL API per la console quando UI e API sono su domini diversi. */\n consoleApiBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n /** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */\n consoleEntry?: ConsoleEntryOptions;\n /** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */\n edgeRateLimit?: AccessiEdgeRateLimitOptions;\n /** CORS, trust proxy e header di sicurezza del servizio. */\n http?: AccessiHttpOptions;\n /** Revoca sessioni per utente tramite store memory/Redis. */\n sessionRevocation?: SessionRevocationOptions;\n /** Refresh token monouso tramite rotazione memory/Redis. */\n refreshTokenRotation?: RefreshTokenRotationOptions;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n FederatedAuthExchangeController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
__ACCESSI_API_BASE_URL__?: string;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
1
6
|
/** Emesso quando una richiesta autenticata riceve 401: la console deve riportare al login. */
|
|
2
7
|
export declare const ACCESSI_UNAUTHORIZED_EVENT = "accessi-console-unauthorized";
|
|
3
8
|
/** Errore del client console: conserva status, codice stabile Accessi e dettagli di validazione. */
|
|
@@ -62,7 +62,7 @@ function payloadString(payload, key) {
|
|
|
62
62
|
*/
|
|
63
63
|
function accessiFetch(url, options) {
|
|
64
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
-
var _a, _b, _c;
|
|
65
|
+
var _a, _b, _c, _d;
|
|
66
66
|
const headers = new Headers(options.headers);
|
|
67
67
|
headers.set('Accept', 'application/json');
|
|
68
68
|
if (options.body !== undefined && !headers.has('Content-Type')) {
|
|
@@ -72,20 +72,23 @@ function accessiFetch(url, options) {
|
|
|
72
72
|
const authenticatedRequest = resolvedToken !== null && resolvedToken !== undefined;
|
|
73
73
|
if (resolvedToken)
|
|
74
74
|
headers.set('Authorization', `Bearer ${resolvedToken}`);
|
|
75
|
-
const
|
|
75
|
+
const runtimeBaseUrl = baseUrl !== null && baseUrl !== void 0 ? baseUrl : (typeof window !== 'undefined' ? (_a = window.__ACCESSI_API_BASE_URL__) !== null && _a !== void 0 ? _a : null : null);
|
|
76
|
+
const requestUrl = runtimeBaseUrl && url.startsWith('/')
|
|
77
|
+
? `${runtimeBaseUrl.replace(/\/+$/, '')}${url}`
|
|
78
|
+
: url;
|
|
76
79
|
notifyNetworkActivity(true);
|
|
77
80
|
try {
|
|
78
81
|
const response = yield fetch(requestUrl, Object.assign(Object.assign({}, options), { headers }));
|
|
79
82
|
const payload = yield response.json().catch(() => undefined);
|
|
80
83
|
if (!response.ok) {
|
|
81
|
-
const message = (
|
|
84
|
+
const message = (_c = (_b = payloadString(payload, 'message')) !== null && _b !== void 0 ? _b : payloadString(payload, 'error')) !== null && _c !== void 0 ? _c : `Errore HTTP ${response.status}`;
|
|
82
85
|
const rawDetails = payload && typeof payload === 'object' ? payload.details : undefined;
|
|
83
86
|
const details = Array.isArray(rawDetails) ? rawDetails.map((item) => String(item)) : undefined;
|
|
84
87
|
// Un 401 su una richiesta autenticata significa sessione scaduta/revocata: il token non e piu valido.
|
|
85
88
|
if (response.status === 401 && authenticatedRequest && typeof window !== 'undefined') {
|
|
86
89
|
window.dispatchEvent(new CustomEvent(exports.ACCESSI_UNAUTHORIZED_EVENT));
|
|
87
90
|
}
|
|
88
|
-
throw new AccessiRequestError(message, response.status, (
|
|
91
|
+
throw new AccessiRequestError(message, response.status, (_d = payloadString(payload, 'code')) !== null && _d !== void 0 ? _d : payloadString(payload, 'error'), details);
|
|
89
92
|
}
|
|
90
93
|
return {
|
|
91
94
|
data: payload,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessiFetch.js","sourceRoot":"","sources":["../../../src/accessi-module/Console/accessiFetch.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"accessiFetch.js","sourceRoot":"","sources":["../../../src/accessi-module/Console/accessiFetch.ts"],"names":[],"mappings":"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","sourcesContent":["let accessToken: string | null = null;\nlet baseUrl: string | null = null;\nlet tokenProvider: (() => string | null | Promise<string | null>) | null = null;\n\ndeclare global {\n interface Window {\n __ACCESSI_API_BASE_URL__?: string;\n }\n}\n\nconst loadingEventName = 'accessi-console-network';\n/** Emesso quando una richiesta autenticata riceve 401: la console deve riportare al login. */\nexport const ACCESSI_UNAUTHORIZED_EVENT = 'accessi-console-unauthorized';\n\n/** Errore del client console: conserva status, codice stabile Accessi e dettagli di validazione. */\nexport class AccessiRequestError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly details?: string[]) {\n super(message);\n this.name = 'AccessiRequestError';\n }\n}\n\n/** Notifies the browser shell without coupling generated Orval calls to the UI implementation. */\nfunction notifyNetworkActivity(active: boolean): void {\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(loadingEventName, { detail: { active } }));\n }\n}\n\n/** Imposta il JWT usato da tutte le funzioni generate da Orval. */\nexport function setAccessiConsoleToken(token: string | null): void {\n accessToken = token;\n}\n\n/** Prefissa le chiamate relative del client generato (es. `https://accessi.example.com`). */\nexport function setAccessiFetchBaseUrl(url: string | null): void {\n baseUrl = url ? url.replace(/\\/+$/, '') : null;\n}\n\n/** Token provider per client esterni alla console (server-to-server o frontend). */\nexport function setAccessiFetchTokenProvider(\n provider: (() => string | null | Promise<string | null>) | null,\n): void {\n tokenProvider = provider;\n}\n\n/** Legge una stringa non vuota dal payload di errore Accessi, ignorando tipi inattesi. */\nfunction payloadString(payload: unknown, key: string): string | undefined {\n if (!payload || typeof payload !== 'object') return undefined;\n const value = (payload as Record<string, unknown>)[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Trasporto comune del client Orval: aggiunge il Bearer token e converte le\n * risposte di errore Accessi in Error JavaScript leggibili dalla console.\n */\nexport async function accessiFetch<T>(url: string, options: RequestInit): Promise<T> {\n const headers = new Headers(options.headers);\n headers.set('Accept', 'application/json');\n if (options.body !== undefined && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n const resolvedToken = tokenProvider ? await tokenProvider() : accessToken;\n const authenticatedRequest = resolvedToken !== null && resolvedToken !== undefined;\n if (resolvedToken) headers.set('Authorization', `Bearer ${resolvedToken}`);\n const runtimeBaseUrl = baseUrl\n ?? (typeof window !== 'undefined' ? window.__ACCESSI_API_BASE_URL__ ?? null : null);\n const requestUrl = runtimeBaseUrl && url.startsWith('/')\n ? `${runtimeBaseUrl.replace(/\\/+$/, '')}${url}`\n : url;\n\n notifyNetworkActivity(true);\n try {\n const response = await fetch(requestUrl, { ...options, headers });\n const payload = await response.json().catch(() => undefined);\n if (!response.ok) {\n const message = payloadString(payload, 'message') ?? payloadString(payload, 'error') ?? `Errore HTTP ${response.status}`;\n const rawDetails = payload && typeof payload === 'object' ? (payload as { details?: unknown }).details : undefined;\n const details = Array.isArray(rawDetails) ? rawDetails.map((item) => String(item)) : undefined;\n // Un 401 su una richiesta autenticata significa sessione scaduta/revocata: il token non e piu valido.\n if (response.status === 401 && authenticatedRequest && typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(ACCESSI_UNAUTHORIZED_EVENT));\n }\n throw new AccessiRequestError(message, response.status, payloadString(payload, 'code') ?? payloadString(payload, 'error'), details);\n }\n return {\n data: payload,\n status: response.status,\n headers: response.headers,\n } as T;\n } finally {\n notifyNetworkActivity(false);\n }\n}\n"]}
|
|
@@ -35,7 +35,8 @@ async function accessiFetch(url, options) {
|
|
|
35
35
|
const resolvedToken = tokenProvider ? await tokenProvider() : accessToken;
|
|
36
36
|
const authenticatedRequest = resolvedToken !== null && resolvedToken !== void 0;
|
|
37
37
|
if (resolvedToken) headers.set("Authorization", `Bearer ${resolvedToken}`);
|
|
38
|
-
const
|
|
38
|
+
const runtimeBaseUrl = baseUrl ?? (typeof window !== "undefined" ? window.__ACCESSI_API_BASE_URL__ ?? null : null);
|
|
39
|
+
const requestUrl = runtimeBaseUrl && url.startsWith("/") ? `${runtimeBaseUrl.replace(/\/+$/, "")}${url}` : url;
|
|
39
40
|
notifyNetworkActivity(true);
|
|
40
41
|
try {
|
|
41
42
|
const response = await fetch(requestUrl, { ...options, headers });
|
|
@@ -1007,6 +1008,7 @@ var WIKI_SECTIONS = [
|
|
|
1007
1008
|
]
|
|
1008
1009
|
),
|
|
1009
1010
|
p(`Topologia consigliata: un solo Accessi Service possiede database, encryptionKey, SMTP, chiavi JWT e console. Gli altri backend usano resource-server e client, senza credenziali del database Accessi.`),
|
|
1011
|
+
p(`Per avviare Accessi come servizio autonomo usare startAccessiService: espone /health/live, /health/ready, /health/metrics, valida la configurazione e gestisce SIGTERM/SIGINT.`),
|
|
1010
1012
|
good("ts", [
|
|
1011
1013
|
"// Backend che ospita Accessi",
|
|
1012
1014
|
"import { initializeAccessiModule } from 'emilsoftware-utilities/accessi/server';",
|
|
@@ -1040,17 +1042,23 @@ var WIKI_SECTIONS = [
|
|
|
1040
1042
|
["passwordExpirationDays", "number", "no", "Valore predefinito: 90 giorni."],
|
|
1041
1043
|
["legacyPasswordMigrationOnStartup", "boolean", "no", "Predefinito true: converte le password legacy."],
|
|
1042
1044
|
["autoUpdateDatabase", "boolean", "no", "Predefinito true: riconcilia lo schema al boot."],
|
|
1043
|
-
["jwtOptions", "{ secret, expiresIn, algorithm, issuer, audience, privateKey, publicKey, keyId }", "s\xEC", "Firma e
|
|
1045
|
+
["jwtOptions", "{ secret, expiresIn, refreshExpiresIn, algorithm, issuer, audience, privateKey, publicKey, keyId, jwksPath, previousPublicKeys }", "s\xEC", "Firma, durata, refresh token e JWKS. Default HS256; RS/ES consigliati per resource server multi-servizio."],
|
|
1044
1046
|
["emailOptions", "EmailOptions", "s\xEC", "SMTP per reset e codici email."],
|
|
1045
|
-
["publicAuthRateLimit", "PublicAuthRateLimitOptions", "no", "Limiti
|
|
1047
|
+
["publicAuthRateLimit", "PublicAuthRateLimitOptions", "no", "Limiti per endpoint pubblici; store condiviso opzionale (Redis) per il cluster."],
|
|
1048
|
+
["edgeRateLimit", "AccessiEdgeRateLimitOptions", "no", "Limite grossolano per IP davanti alle rotte Accessi; opzionale, store condiviso supportato."],
|
|
1049
|
+
["http", "{ cors, trustProxy, securityHeaders }", "no", "CORS, IP reali dietro proxy e header di sicurezza del servizio."],
|
|
1046
1050
|
["publicRegistration", "{ enabled }", "no", "Registrazione pubblica: disattivata per impostazione predefinita."],
|
|
1047
1051
|
["federatedAuthentication", "FederatedAuthenticationOptions", "no", `Abilita l'SSO generico.`],
|
|
1048
1052
|
["extensionFieldsOptions", "ExtensionFieldsOptions[]", "no", "Tabelle esterne allegate al profilo."],
|
|
1049
|
-
["serviceTokens", "{ enabled, defaultTtlDays }", "no", "Token macchina-a-macchina, abilitati per impostazione predefinita."],
|
|
1053
|
+
["serviceTokens", "{ enabled, defaultTtlDays, rateLimitStore }", "no", "Token macchina-a-macchina, abilitati per impostazione predefinita; rate limit condiviso opzionale."],
|
|
1050
1054
|
["catalogScripts", "{ enabled, folder, ... }", "no", "Catalog migrations SQL eseguite dopo la riconciliazione dello schema."],
|
|
1051
1055
|
["adminBootstrap", "{ enabled, superUser }", "no", "Token casuale a ogni avvio per creare il primo admin dalla console."],
|
|
1052
1056
|
["publicBaseUrl", "string", "no", "Base URL usata solo per loggare console/OpenAPI/API."],
|
|
1057
|
+
["consoleApiBaseUrl", "string", "no", "Base URL API per la console quando UI e API sono su domini diversi."],
|
|
1053
1058
|
["openapi", "OpenApiSetupOptions", "no", "Path, titolo, descrizione e enabled della documentazione OpenAPI. Default invariati."],
|
|
1059
|
+
["consoleEntry", "{ ttlMs, store }", "no", "TTL e store condiviso dei ticket console (Redis per multi-istanza). Default in memoria."],
|
|
1060
|
+
["sessionRevocation", "{ enabled, store, ttlMs }", "no", "Revoca sessioni per utente tramite store memory/Redis; abilita POST /api/accessi/auth/revoke-sessions."],
|
|
1061
|
+
["refreshTokenRotation", "{ enabled, store }", "no", "Refresh token monouso tramite store memory/Redis; consigliato in multi-istanza."],
|
|
1054
1062
|
["logger", "LoggerService", "no", "Logger Nest del sotto-app; se assente Nest usa il proprio logger."],
|
|
1055
1063
|
["bufferLogs", "boolean", "no", "Buffer dei log di bootstrap del sotto-app. Default true."]
|
|
1056
1064
|
]
|
|
@@ -1334,7 +1342,9 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1334
1342
|
]
|
|
1335
1343
|
),
|
|
1336
1344
|
note("warn", `Fail closed`, `Se introspection e configurata ma non raggiungibile, il resource server risponde 503. Non autorizza la richiesta.`),
|
|
1337
|
-
note("info", `Introspection`, `POST /api/accessi/auth/introspect restituisce active=false per token invalido, scaduto o utente disabilitato. I risultati attivi sono cachati lato resource server per 30 secondi per default.`)
|
|
1345
|
+
note("info", `Introspection`, `POST /api/accessi/auth/introspect restituisce active=false per token invalido, scaduto o utente disabilitato. I risultati attivi sono cachati lato resource server per 30 secondi per default.`),
|
|
1346
|
+
note("info", `JWKS`, `Con RS256/ES256 Accessi pubblica la JWKS su /accessi/.well-known/jwks.json (configurabile con jwtOptions.jwksPath). Il resource server puo usare jwks.url e ruotare le chiavi con previousPublicKeys.`),
|
|
1347
|
+
note("info", `Audit`, `I fallimenti di autenticazione del resource server e i blocchi edge producono eventi strutturati tramite auditAccessi; i token e i segreti vengono redatti dal Logger.`)
|
|
1338
1348
|
]
|
|
1339
1349
|
},
|
|
1340
1350
|
// -------------------------------------------------------------------------
|
|
@@ -1533,6 +1543,7 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1533
1543
|
"}",
|
|
1534
1544
|
"return res.json({ login: result.login, token: result.token });"
|
|
1535
1545
|
].join("\n"), "Login SSO"),
|
|
1546
|
+
note("info", `Scambio service-to-service`, `Se il backend fratello valida il provider SSO, pu\xF2 scambiare { provider, subject } con POST /api/accessi/federated-auth/exchange usando un service token con scope accessi:federated:exchange. Accessi non riceve il token del provider.`),
|
|
1536
1547
|
h(`API amministrative (superutente)`),
|
|
1537
1548
|
list([
|
|
1538
1549
|
`GET/POST /api/accessi/federated-auth/providers, PATCH/DELETE providers/:provider`,
|
|
@@ -1557,6 +1568,8 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1557
1568
|
p(`Formato: st_<id>.<segreto> (segreto da 256 bit). Nel database si salva solo lo SHA-256 del segreto; il segreto \xE8 mostrato una sola volta. La verifica restituisce { tokenId, label, scopes }: nessun ruolo o grant.`),
|
|
1558
1569
|
note("danger", `Non \xE8 un superutente`, `Un service token non apre le API Accessi: abilita solo le rotte della tua app che proteggi con ServiceTokenGuard.`),
|
|
1559
1570
|
note("info", `Introspection`, `Per un backend fratello creare un service token con scope accessi:introspect e usarlo in POST /api/accessi/auth/introspect. Il resource server lo configura in introspection.serviceToken.`),
|
|
1571
|
+
note("warn", `Rate limit condiviso`, `In cluster configurare serviceTokens.rateLimitStore e publicAuthRateLimit.store con createRedisRateLimitStore: i contatori in memoria valgono solo per singola istanza.`),
|
|
1572
|
+
note("info", `Edge rate limit`, `Per una soglia grossolana per IP configurare edgeRateLimit: viene applicata davanti alle rotte Accessi. Il gateway/API gateway resta comunque consigliato per bot protection e limiti di connessione.`),
|
|
1560
1573
|
good("ts", [
|
|
1561
1574
|
"import { ServiceTokenGuard, RequireServiceTokenScopes } from 'emilsoftware-utilities';",
|
|
1562
1575
|
"",
|
|
@@ -1604,7 +1617,8 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1604
1617
|
note("info", `Accesso`, `Apri /api/accessi/console e accedi con un utente con FLGSUPER o FLGADMIN. Le sezioni sono raggiungibili anche tramite deep link (per esempio /api/accessi/console/menu-e-gruppi/menu).`),
|
|
1605
1618
|
note("info", `Bootstrap admin`, `Con adminBootstrap.enabled il backend stampa a ogni avvio un token casuale (monouso, valido fino al riavvio). La sezione "Crea utente admin" nella schermata di login compare solo quando adminBootstrap \xE8 abilitato (stato esposto da GET /api/accessi/auth/bootstrap-admin/status): incolla il token e crea il primo admin senza email di conferma. La password \xE8 opzionale: se assente viene generata e mostrata una sola volta.`),
|
|
1606
1619
|
note("ok", `Auto-ingresso dal frontend`, `Se un frontend ha gi\xE0 una sessione Accessi valida e l'utente \xE8 abilitato alla console, pu\xF2 aprire la console senza rifare il login: \`POST /api/accessi/console/entry\` con \`Authorization: Bearer <jwt>\` restituisce un ticket monouso; apri poi \`/api/accessi/console#entry=<ticket>\`. Il JWT non finisce mai nell'URL; il ticket dura 60 secondi ed \xE8 utilizzabile una sola volta (endpoint di scambio protetto da rate limit).`),
|
|
1607
|
-
note("info", `Console centralizzata`, `In una topologia multi-backend la console va ospitata una sola volta su Accessi Service. Gli altri backend possono linkarla con \`buildAccessiConsoleUrl\` di \`accessi/console\` oppure proxare \`/api/accessi/*\` sullo stesso dominio. Non copiare gli asset della console in ogni applicazione.`)
|
|
1620
|
+
note("info", `Console centralizzata`, `In una topologia multi-backend la console va ospitata una sola volta su Accessi Service. Gli altri backend possono linkarla con \`buildAccessiConsoleUrl\` di \`accessi/console\` oppure proxare \`/api/accessi/*\` sullo stesso dominio. Non copiare gli asset della console in ogni applicazione.`),
|
|
1621
|
+
note("warn", `Ticket multi-istanza`, `I ticket di ingresso console sono in memoria per default. Con piu istanze configurare \`consoleEntry.store\` con \`createRedisConsoleEntryStore\`: il JWT viene cifrato e il consume e atomico.`)
|
|
1608
1622
|
]
|
|
1609
1623
|
},
|
|
1610
1624
|
// -------------------------------------------------------------------------
|
|
@@ -1771,7 +1785,7 @@ function buildAiDigest() {
|
|
|
1771
1785
|
}
|
|
1772
1786
|
|
|
1773
1787
|
// src/accessi-module/Console/changelog.md
|
|
1774
|
-
var changelog_default = "# Changelog Accessi\n\nNovit\xE0 e modifiche rilevanti della libreria `emilsoftware-utilities` (modulo Accessi).\n\n## Non rilasciato\n\n### Cambiamenti\n- Distribuzione: nuovi entry point `accessi/server`, `accessi/resource-server`, `accessi/client`, `accessi/contracts`, `accessi/contracts/dtos`, `accessi/openapi`, `accessi/console` e `accessi/ui`. Gli entry point sono dichiarati in `package.json#exports`; il root export resta per retrocompatibilita.\n- Resource server: aggiunti `createAccessiAuthMiddleware`, `createAccessiAuthGuard`, `createAccessiTokenVerifier` e `createAccessiIntrospectionClient` per backend fratelli che non possiedono il database Accessi. Supporta HS256, RS/ES con chiave pubblica PEM e JWKS con cache.\n- Introspection: nuovo `POST /api/accessi/auth/introspect` protetto da service token con scope `accessi:introspect`. Restituisce `active`, profilo utente e grant correnti.\n- JWT: `jwtOptions` accetta `algorithm`, `issuer`, `audience`, `privateKey`, `publicKey` e `keyId`. Default HS256 invariato; RS/ES sono consigliati per la topologia multi-servizio.\n- OpenAPI: aggiunto `mergeOpenApiDocuments` per unire il documento Accessi nel documento unico dell'host con conflitti espliciti.\n- Console: aggiunto `buildAccessiConsoleUrl` per linkare la console centrale senza mettere JWT nell'URL.\n- Rinomina: la configurazione e gli helper della documentazione usano `openapi`/`OpenApi` (`AccessiOptions.openapi`, `OpenApiSetupOptions`, `setupOpenApi`, `DEFAULT_ACCESSI_OPENAPI`); i vecchi nomi `swagger` non sono piu esportati.\n- Token Accessi: `TokenResult.expiresIn` riporta sempre la validita effettiva in secondi (es. `86400`), anche quando `jwtOptions.expiresIn` usa un formato leggibile come `24h`. I client possono quindi esporre `expires_in` anche per il token di login normale.\n- Console: nuova funzione **Login as** per superutenti e admin. Dalla lista utenti si genera un URL verso l'applicazione scelta con `?loginAsToken=<jwt>`; il token dura quanto la sessione Accessi standard (`jwtOptions.expiresIn`), registra l'attore nelle claim `act`/`loginAs` e resta soggetto alla gerarchia ADMIN > SUPER. Endpoint: `POST /api/accessi/user/login-as/:codiceUtente`.\n- Console: rimosse le sezioni **Filtri utente** e **Tipi filtro**. I filtri applicativi sono deprecati e non vengono pi\xF9 letti n\xE9 scritti dalla console; le tabelle restano invariate e la gestione torna manuale sul database.\n- Console: le conferme operative (es. \"Ruoli aggiornati\") ora compaiono come notifiche in alto a destra e scompaiono automaticamente.\n- Console: il salvataggio del profilo non invia pi\xF9 i campi della tabella `FILTRI`, evitando payload rifiutati dal backend. `UserService` tocca `FILTRI` solo se il chiamante invia esplicitamente almeno un campo legacy.\n- Console: scheda utente riorganizzata. \"Indietro\" resta nella barra superiore; stato registrazione, disattivazione ed eliminazione definitiva sono in un form coerente \"Stato e sicurezza\", con icone e tooltip allineati.\n- Console: pagina Changelog a larghezza piena, con intestazioni di versione evidenziate e sezioni orizzontali leggibili.\n- Seed `npm run accessi:seed-admin`: crea o aggiorna un admin completo (`FLGSUPER = 1` e `FLGADMIN = 1`) e corregge il nome colonna usato in precedenza (`FLGADMIN`).\n- Console: la pagina di default nella scheda utente \xE8 ora un autocomplete con ricerca. Propone tutte le rotte del catalogo menu, si filtra scrivendo ed \xE8 ancora possibile inserire un valore libero.\n- Autorizzazioni: i grant effettivi sommano ruoli e permessi diretti prendendo il livello massimo per menu. Un permesso diretto con livello inferiore (o 0) non annulla pi\xF9 il grant del ruolo.\n- Ruoli legacy: un menu senza descrizione non viene pi\xF9 scartato e un `TIPABI` mancante viene letto come livello 10, evitando utenti con ruolo ma senza accesso.\n- Grant dei ruoli arricchiti con i metadati di navigazione del catalogo menu (`pagina`, icona, gruppo, tipo): il frontend riceve gli stessi campi dei grant diretti e pu\xF2 costruire correttamente menu e rotte.\n- Sicurezza: `GET /api/accessi/permission/grants/:codiceUtente` accetta solo un JWT Accessi valido e consente la lettura solo al proprietario o a chi pu\xF2 gestire quel target (gerarchia ADMIN > SUPER). Un superutente non pu\xF2 leggere i grant di un admin.\n\n## 2.0.0-dev.50 (2026-10-15)\n\n### Cambiamenti\n- ORM: `Row` e `DbValue` sono i tipi predefiniti di `Orm.query` e `Orm.execute`; `transactionQuery` usa `Row[]`. Gli usi generici non devono pi\xF9 dichiarare `Record<string, unknown>`.\n- Build: il contratto OpenAPI generato (`src/accessi-module/openapi/`) \xE8 ignorato da Git e viene rigenerato da `npm run generate:accessi-openapi`.\n\n## 2.0.0-dev.49 (2026-10-15)\n\n### Cambiamenti\n- Documentazione HTTP rinominata da Swagger a **OpenAPI**: il modulo unificato espone `/accessi/openapi` e `/accessi/openapi.json`; `setupSwagger` usa `/openapi` come default.\n- Il path \xE8 configurabile tramite `EmilsoftwareOptions.swagger` (utile per far convivere pi\xF9 documentazioni).\n- Allineati log di avvio, Wiki e dispatch delle rotte del modulo.\n- L'alias storico `<path>-json` resta supportato.\n\n### Note\n- I consumer che aprivano `/swagger` o `/accessi/swagger` devono aggiornare l'URL alla nuova documentazione OpenAPI.\n\n## 2.0.0-dev.48 (2026-10-13)\n\n### Correzioni\n- `RestUtilities.sendErrorMessage` restituisce status HTTP specifici (400/401/403/4xx/5xx) e codici generici (`VALIDATION_ERROR`, `UNAUTHORIZED`, `FORBIDDEN`, `INTERNAL_ERROR`, `REQUEST_ERROR`), senza usare codici `ACCESSI_*` nel business helper.\n- Il messaggio restituito \xE8 quello reale dell'eccezione; gli errori testuali di validazione vengono riconosciuti come 400.\n\n## 2.0.0-dev.47 (2026-10-13)\n\n### Correzioni\n- Errore schema database reso generico: codice `DATABASE_SCHEMA_OUTDATED` e messaggio senza riferimenti specifici ad Accessi.\n\n## 2.0.0-dev.46 (2026-10-12)\n\n### Correzioni\n- `sendBaseResponse` resta retro-compatibile quando il terzo argomento \xE8 un tag stringa invece dello status HTTP.\n- Gestita la serializzazione dei `bigint`; gli errori di risposta vengono registrati con stack tramite `sendErrorMessage`.\n- `AccessiHttpExceptionFilter` registra gli errori con stack per facilitare la diagnosi.\n\n## 2.0.0-dev.45 (2026-10-12)\n\n### Correzioni\n- `set-gdpr` e l'aggiornamento di `flagGdpr` sono idempotenti: `UPDATE OR INSERT` su `UTENTI_GDPR` con `MATCHING (CODUTE, DATACC)`.\n- Evitate violazioni di chiave primaria e risposte 500 quando il consenso GDPR viene registrato pi\xF9 volte nello stesso giorno.\n\n## 2.0.0-dev.44\n\n### Aggiunte\n- Endpoint pubblico `GET /api/accessi/auth/bootstrap-admin/status` (`getAdminBootstrapStatus`): la console mostra la sezione \"Crea utente admin\" **solo** se `adminBootstrap.enabled` \xE8 `true`.\n\n### Correzioni\n- Rimossi i caratteri corrotti (mojibake UTF-8 \u2194 Windows-1252) da DTO, servizi, controller, console, OpenAPI e client generato (es. \"L'email \xE8 gi\xE0 associata a un utente Accessi.\").\n\n## 2.0.0-dev.43\n\n### Cambiamenti\n- Gerarchia dei ruoli formalizzata **ADMIN > SUPER > utente**: un superutente non puo' gestire un admin su `update-user`, `delete-user` (soft e hard), `set-password`, `force-password-reset`, `set-stato`, `assign-roles` e `assign-permissions` (`ensureCanManageTargetUser`, 403 se violato).\n- Guard **ultimo admin attivo**: non puo' essere disattivato, bloccato, eliminato o privato del flag Admin (400), per evitare il lockout della console.\n- Creazione utente (`create-managed-user` e registrazione pubblica) resa **atomica** rispetto all'invio email: fail-fast se SMTP non configurato e rollback dell'utente creato se l'invio fallisce (`ACCESSI_USER_INVITE_EMAIL_FAILED`).\n- Console: form password separato (Invio imposta la password invece di salvare il profilo), scheda utente in sola lettura per target di rango superiore.\n- SSO: anche il superutente puo' creare utenti SSO e gestirne identita/policy (`federated-auth/users/*`) sugli utenti non-admin; il catalogo dei provider SSO resta riservato agli admin.\n- Coerenza: i filtri utente (`saveFiltriUtente`) rispettano la gerarchia; il flag GDPR impostato dal profilo allinea anche `DATGDPR`; la scheda in sola lettura disabilita anche il collegamento SSO.\n- Eliminazione definitiva: se l'utente ha dati collegati (tabelle esterne/FK) risponde 400 con `code: ACCESSI_USER_DELETE_HAS_REFERENCES` e messaggio esplicito, suggerendo il soft delete (la hard delete resta invariata quando non ci sono vincoli).\n- Consenso GDPR completo: `update-user` con `flagGdpr` scrive anche la riga storica `UTENTI_GDPR`; in console il pulsante \"Registra consenso GDPR\" usa `set-gdpr`.\n- Console: aggiunto il pulsante \"Invia reset password legacy\" (super e admin).\n- Console: **auto-ingresso dal frontend** tramite ticket monouso (`POST /api/accessi/console/entry` + apertura di `#entry=<ticket>`), senza JWT nell'URL; il ticket e' legato all'utente, dura 60s, e' monouso e lo scambio e' protetto da rate limit (`publicAuthRateLimit.consoleEntry`).\n\n## 2.0.0-dev.42\n\n### Aggiunte\n- Gestione dei flag di privilegio dalla console Accessi:\n - un admin pu\xF2 assegnare o togliere sia `FLGADMIN` sia `FLGSUPER`;\n - un superutente senza `FLGADMIN` pu\xF2 gestire solo `FLGSUPER`;\n - i flag sono impostabili in creazione (utente locale o SSO) e in modifica profilo.\n- Eliminazione utenti con due modalit\xE0:\n - soft delete (`delete-user`, `STAREG=DELETE`) per admin e superutenti;\n - eliminazione definitiva (`delete-user-permanent`, solo admin) che rimuove in transazione utente e record collegati.\n- Gestione completa dell'utente dalla console (admin): anagrafica estesa (cellulare, lingua, avatar, metadata JSON), GDPR, scadenza password, tutti i filtri (`FILTRI`) e **impostazione diretta della password** (`POST /api/accessi/user/set-password/:codiceUtente`), senza accesso al database.\n- Scritture utente idempotenti: `UTENTI_CONFIG` in `UPDATE OR INSERT ... MATCHING (CODUTE)`; i campi non inviati restano invariati.\n- Policy password moderna quando si imposta una password (reset, set-password admin, bootstrap): minimo 8 caratteri con maiuscola, minuscola, cifra e carattere speciale, senza spazi e non comune. In caso di violazione risposta 400 con `code: ACCESSI_WEAK_PASSWORD` e `details`. La policy **non** si applica al login, cos\xEC le password preesistenti deboli continuano a funzionare.\n\n### Correzioni\n- Il backend verifica i flag in base al ruolo dell'utente connesso (`ensurePrivilegeFlagChanges`): inviare un flag non consentito restituisce 403.\n\n## 2.0.0-dev.33\n\n### Cambiamenti\n- Rimosse le logiche applicative residue dallo schema Accessi:\n - `MENU_GRP.NOMECAMPO`\n - `UTENTI.ENABLEIA`\n - `UTENTI_CONFIG.PAGDEF`\n - `UTENTI.CELLUTE`\n- Telefono canonico: `UTENTI_CONFIG.CELLULARE` (allargato a `VARCHAR(30)`).\n- Migrazione automatica: copia `UTENTI.CELLUTE` \u2192 `UTENTI_CONFIG.CELLULARE`, poi `DROP` delle colonne obsolete.\n- Ruoli chiariti:\n - `FLGSUPER`: superutente, riceve **tutte** le abilitazioni al livello massimo (30) dopo il login; in console vede **solo** la sezione **Utenti**.\n - `FLGADMIN`: accede a **tutta** la console (catalogo, token, SSO, utenti) ma **non** influisce sulle abilitazioni.\n- Aggiunta la sezione **Changelog** in console (sotto la Wiki).\n\n### Note\n- `FILTRI` e `FILTRI_TIPO` restano invariati (piano di migrazione futuro).\n- I backend che usavano i campi rimossi devono gestirli in tabelle proprie.\n\n## 2.0.0-dev.32\n\n### Cambiamenti\n- Rimosso il supporto ai flag applicativi in `UTENTI_CONFIG`: `FLGMOP`, `FLGPIANA`, `FLGADDETTI`, `FLGOSPITI`, `FLGPIANARFID`, `FLGCONTA`, `FLGCUBI`, `FLGCICLPASS`, `FLGDIPENDENTI`, `FLGINVENTARI`, `CAUMOV`, `NUMMAC`, `RAGSOCCLI`.\n- Rinominata la colonna `FLGADMINCONFIG` in `FLGADMIN` (con copia dei valori e `DROP`).\n\n## 2.0.0-dev.31\n\n### Aggiunte\n- Esposizione dei servizi Accessi all'host Express (`getAccessiModuleServices`) per delegare login, SSO e token senza reimplementarli.\n\n### Correzioni\n- `UserService.getUsers`: filtri estesi (`codiceUtente[]`, `numRep[]`, `codDipendente`, `cellulare`, `tipFil`, `flagSuper`).\n\n## 2.0.0-dev.24\n\n### Cambiamenti (breaking)\n- Chiavi JWT derivate per scopo (`access`, `reset`, `2fa`) e claim `typ` obbligatorio: gli access token precedenti non sono pi\xF9 validi.\n- Endpoint Allegati protetti di default.\n- Pool di connessioni attivo di default (`poolSize` 5).\n\n### Aggiunte\n- Service token macchina-a-macchina (gestione, guard, console).\n- CRUD completo dei cataloghi dalla console Accessi.\n- Supporto Firebird 2.5 nel migrator e nei test di integrazione.\n";
|
|
1788
|
+
var changelog_default = "# Changelog Accessi\n\nNovit\xE0 e modifiche rilevanti della libreria `emilsoftware-utilities` (modulo Accessi).\n\n## Non rilasciato\n\n### Cambiamenti\n- Distribuzione: nuovi entry point `accessi/server`, `accessi/resource-server`, `accessi/client`, `accessi/contracts`, `accessi/contracts/dtos`, `accessi/openapi`, `accessi/console` e `accessi/ui`. Gli entry point sono dichiarati in `package.json#exports`; il root export resta per retrocompatibilita.\n- Resource server: aggiunti `createAccessiAuthMiddleware`, `createAccessiAuthGuard`, `createAccessiTokenVerifier` e `createAccessiIntrospectionClient` per backend fratelli che non possiedono il database Accessi. Supporta HS256, RS/ES con chiave pubblica PEM e JWKS con cache.\n- Introspection: nuovo `POST /api/accessi/auth/introspect` protetto da service token con scope `accessi:introspect`. Restituisce `active`, profilo utente e grant correnti.\n- JWT: `jwtOptions` accetta `algorithm`, `issuer`, `audience`, `privateKey`, `publicKey`, `keyId`, `jwksPath` e `previousPublicKeys`. Default HS256 invariato; RS/ES sono consigliati per la topologia multi-servizio.\n- JWKS: con RS/ES Accessi pubblica `/accessi/.well-known/jwks.json` (path configurabile) con chiave corrente e chiavi precedenti per la rotazione. I resource server possono usare `jwks.url`.\n- Console ticket: introdotto `ConsoleEntryStore`. Default in memoria; `createRedisConsoleEntryStore` salva il JWT cifrato in Redis, usa TTL e consume atomico per il monouso multi-istanza. Configurazione in `consoleEntry.store` e `consoleEntry.ttlMs`.\n- Rate limit: introdotto `RateLimitStore`. `createRedisRateLimitStore` usa `INCR` + `PEXPIRE` atomici per contatori condivisi in cluster. Configurazione in `publicAuthRateLimit.store` e `serviceTokens.rateLimitStore`; default in memoria invariato.\n- Edge rate limit: aggiunto `createAccessiEdgeRateLimitMiddleware` e `AccessiOptions.edgeRateLimit` per una soglia grossolana per IP davanti alle rotte Accessi. Fail closed se lo store non risponde; supporta lo stesso store Redis.\n- Servizio standalone: aggiunti `createAccessiService`, `startAccessiService`, `/health/live`, `/health/ready`, `/health/metrics` e shutdown graceful. Aggiunti gli script `accessi:serve` e `accessi:serve:dist` per l'esecuzione come processo Node.\n- Configurazione: aggiunti `validateAccessiOptions` e `assertValidAccessiOptions`; il servizio standalone li applica al bootstrap.\n- HTTP: aggiunte opzioni `http.cors`, `http.trustProxy`, `http.securityHeaders`. La JWKS viene montata automaticamente anche con `AccessiModule.forRoot` tramite `HttpAdapterHost`.\n- SSO: aggiunto `POST /api/accessi/federated-auth/exchange` protetto da service token con scope `accessi:federated:exchange` per scambiare `{ provider, subject }` verificati da un backend fratello.\n- Audit: aggiunto `auditAccessi` per eventi di sicurezza strutturati; resource server ed edge rate limit registrano fallimenti di autenticazione, blocchi e rate limit non disponibile.\n- Contratto: aggiunto `npm run check:accessi-openapi`, eseguito nel build, che blocca path fuori prefisso, operationId duplicati/mancanti, $ref rotti, path legacy e rimozioni di operation/schema rispetto al fingerprint versionato.\n- Contratto: aggiunto `npm run accessi:update-openapi-fingerprint` per aggiornare intenzionalmente il fingerprint dopo una modifica breaking approvata.\n- Console: aggiunto `consoleApiBaseUrl` per servire UI e API su domini diversi; il valore viene iniettato in `window.__ACCESSI_API_BASE_URL__`.\n- Chiavi: aggiunto `npm run accessi:generate-jwt-keys` per generare coppia RS256/ES256, `keyId` e JWKS pubblica.\n- Sessioni: aggiunta la revoca per utente con `SessionRevocationStore` memory/Redis e `POST /api/accessi/auth/revoke-sessions`. Resource server e guard controllano il cutoff `iat`.\n- Refresh token: con `jwtOptions.refreshExpiresIn` login, 2FA e SSO emettono anche `refreshToken` (typ=refresh) e `POST /api/accessi/auth/refresh` restituisce una nuova coppia access+refresh. Gli access token hanno ora `jti`.\n- Refresh rotation: con `refreshTokenRotation.store` il refresh token e monouso e la rotazione e atomica tra istanze; due refresh concorrenti producono un solo successo.\n- Contratto: il fingerprint OpenAPI ora blocca anche la rimozione di operation/schema rispetto alla baseline versionata.\n- OpenAPI: aggiunto `mergeOpenApiDocuments` per unire il documento Accessi nel documento unico dell'host con conflitti espliciti.\n- Console: aggiunto `buildAccessiConsoleUrl` per linkare la console centrale senza mettere JWT nell'URL.\n- Rinomina: la configurazione e gli helper della documentazione usano `openapi`/`OpenApi` (`AccessiOptions.openapi`, `OpenApiSetupOptions`, `setupOpenApi`, `DEFAULT_ACCESSI_OPENAPI`); i vecchi nomi `swagger` non sono piu esportati.\n- Token Accessi: `TokenResult.expiresIn` riporta sempre la validita effettiva in secondi (es. `86400`), anche quando `jwtOptions.expiresIn` usa un formato leggibile come `24h`. I client possono quindi esporre `expires_in` anche per il token di login normale.\n- Console: nuova funzione **Login as** per superutenti e admin. Dalla lista utenti si genera un URL verso l'applicazione scelta con `?loginAsToken=<jwt>`; il token dura quanto la sessione Accessi standard (`jwtOptions.expiresIn`), registra l'attore nelle claim `act`/`loginAs` e resta soggetto alla gerarchia ADMIN > SUPER. Endpoint: `POST /api/accessi/user/login-as/:codiceUtente`.\n- Console: rimosse le sezioni **Filtri utente** e **Tipi filtro**. I filtri applicativi sono deprecati e non vengono pi\xF9 letti n\xE9 scritti dalla console; le tabelle restano invariate e la gestione torna manuale sul database.\n- Console: le conferme operative (es. \"Ruoli aggiornati\") ora compaiono come notifiche in alto a destra e scompaiono automaticamente.\n- Console: il salvataggio del profilo non invia pi\xF9 i campi della tabella `FILTRI`, evitando payload rifiutati dal backend. `UserService` tocca `FILTRI` solo se il chiamante invia esplicitamente almeno un campo legacy.\n- Console: scheda utente riorganizzata. \"Indietro\" resta nella barra superiore; stato registrazione, disattivazione ed eliminazione definitiva sono in un form coerente \"Stato e sicurezza\", con icone e tooltip allineati.\n- Console: pagina Changelog a larghezza piena, con intestazioni di versione evidenziate e sezioni orizzontali leggibili.\n- Seed `npm run accessi:seed-admin`: crea o aggiorna un admin completo (`FLGSUPER = 1` e `FLGADMIN = 1`) e corregge il nome colonna usato in precedenza (`FLGADMIN`).\n- Console: la pagina di default nella scheda utente \xE8 ora un autocomplete con ricerca. Propone tutte le rotte del catalogo menu, si filtra scrivendo ed \xE8 ancora possibile inserire un valore libero.\n- Autorizzazioni: i grant effettivi sommano ruoli e permessi diretti prendendo il livello massimo per menu. Un permesso diretto con livello inferiore (o 0) non annulla pi\xF9 il grant del ruolo.\n- Ruoli legacy: un menu senza descrizione non viene pi\xF9 scartato e un `TIPABI` mancante viene letto come livello 10, evitando utenti con ruolo ma senza accesso.\n- Grant dei ruoli arricchiti con i metadati di navigazione del catalogo menu (`pagina`, icona, gruppo, tipo): il frontend riceve gli stessi campi dei grant diretti e pu\xF2 costruire correttamente menu e rotte.\n- Sicurezza: `GET /api/accessi/permission/grants/:codiceUtente` accetta solo un JWT Accessi valido e consente la lettura solo al proprietario o a chi pu\xF2 gestire quel target (gerarchia ADMIN > SUPER). Un superutente non pu\xF2 leggere i grant di un admin.\n\n## 2.0.0-dev.50 (2026-10-15)\n\n### Cambiamenti\n- ORM: `Row` e `DbValue` sono i tipi predefiniti di `Orm.query` e `Orm.execute`; `transactionQuery` usa `Row[]`. Gli usi generici non devono pi\xF9 dichiarare `Record<string, unknown>`.\n- Build: il contratto OpenAPI generato (`src/accessi-module/openapi/`) \xE8 ignorato da Git e viene rigenerato da `npm run generate:accessi-openapi`.\n\n## 2.0.0-dev.49 (2026-10-15)\n\n### Cambiamenti\n- Documentazione HTTP rinominata da Swagger a **OpenAPI**: il modulo unificato espone `/accessi/openapi` e `/accessi/openapi.json`; `setupSwagger` usa `/openapi` come default.\n- Il path \xE8 configurabile tramite `EmilsoftwareOptions.swagger` (utile per far convivere pi\xF9 documentazioni).\n- Allineati log di avvio, Wiki e dispatch delle rotte del modulo.\n- L'alias storico `<path>-json` resta supportato.\n\n### Note\n- I consumer che aprivano `/swagger` o `/accessi/swagger` devono aggiornare l'URL alla nuova documentazione OpenAPI.\n\n## 2.0.0-dev.48 (2026-10-13)\n\n### Correzioni\n- `RestUtilities.sendErrorMessage` restituisce status HTTP specifici (400/401/403/4xx/5xx) e codici generici (`VALIDATION_ERROR`, `UNAUTHORIZED`, `FORBIDDEN`, `INTERNAL_ERROR`, `REQUEST_ERROR`), senza usare codici `ACCESSI_*` nel business helper.\n- Il messaggio restituito \xE8 quello reale dell'eccezione; gli errori testuali di validazione vengono riconosciuti come 400.\n\n## 2.0.0-dev.47 (2026-10-13)\n\n### Correzioni\n- Errore schema database reso generico: codice `DATABASE_SCHEMA_OUTDATED` e messaggio senza riferimenti specifici ad Accessi.\n\n## 2.0.0-dev.46 (2026-10-12)\n\n### Correzioni\n- `sendBaseResponse` resta retro-compatibile quando il terzo argomento \xE8 un tag stringa invece dello status HTTP.\n- Gestita la serializzazione dei `bigint`; gli errori di risposta vengono registrati con stack tramite `sendErrorMessage`.\n- `AccessiHttpExceptionFilter` registra gli errori con stack per facilitare la diagnosi.\n\n## 2.0.0-dev.45 (2026-10-12)\n\n### Correzioni\n- `set-gdpr` e l'aggiornamento di `flagGdpr` sono idempotenti: `UPDATE OR INSERT` su `UTENTI_GDPR` con `MATCHING (CODUTE, DATACC)`.\n- Evitate violazioni di chiave primaria e risposte 500 quando il consenso GDPR viene registrato pi\xF9 volte nello stesso giorno.\n\n## 2.0.0-dev.44\n\n### Aggiunte\n- Endpoint pubblico `GET /api/accessi/auth/bootstrap-admin/status` (`getAdminBootstrapStatus`): la console mostra la sezione \"Crea utente admin\" **solo** se `adminBootstrap.enabled` \xE8 `true`.\n\n### Correzioni\n- Rimossi i caratteri corrotti (mojibake UTF-8 \u2194 Windows-1252) da DTO, servizi, controller, console, OpenAPI e client generato (es. \"L'email \xE8 gi\xE0 associata a un utente Accessi.\").\n\n## 2.0.0-dev.43\n\n### Cambiamenti\n- Gerarchia dei ruoli formalizzata **ADMIN > SUPER > utente**: un superutente non puo' gestire un admin su `update-user`, `delete-user` (soft e hard), `set-password`, `force-password-reset`, `set-stato`, `assign-roles` e `assign-permissions` (`ensureCanManageTargetUser`, 403 se violato).\n- Guard **ultimo admin attivo**: non puo' essere disattivato, bloccato, eliminato o privato del flag Admin (400), per evitare il lockout della console.\n- Creazione utente (`create-managed-user` e registrazione pubblica) resa **atomica** rispetto all'invio email: fail-fast se SMTP non configurato e rollback dell'utente creato se l'invio fallisce (`ACCESSI_USER_INVITE_EMAIL_FAILED`).\n- Console: form password separato (Invio imposta la password invece di salvare il profilo), scheda utente in sola lettura per target di rango superiore.\n- SSO: anche il superutente puo' creare utenti SSO e gestirne identita/policy (`federated-auth/users/*`) sugli utenti non-admin; il catalogo dei provider SSO resta riservato agli admin.\n- Coerenza: i filtri utente (`saveFiltriUtente`) rispettano la gerarchia; il flag GDPR impostato dal profilo allinea anche `DATGDPR`; la scheda in sola lettura disabilita anche il collegamento SSO.\n- Eliminazione definitiva: se l'utente ha dati collegati (tabelle esterne/FK) risponde 400 con `code: ACCESSI_USER_DELETE_HAS_REFERENCES` e messaggio esplicito, suggerendo il soft delete (la hard delete resta invariata quando non ci sono vincoli).\n- Consenso GDPR completo: `update-user` con `flagGdpr` scrive anche la riga storica `UTENTI_GDPR`; in console il pulsante \"Registra consenso GDPR\" usa `set-gdpr`.\n- Console: aggiunto il pulsante \"Invia reset password legacy\" (super e admin).\n- Console: **auto-ingresso dal frontend** tramite ticket monouso (`POST /api/accessi/console/entry` + apertura di `#entry=<ticket>`), senza JWT nell'URL; il ticket e' legato all'utente, dura 60s, e' monouso e lo scambio e' protetto da rate limit (`publicAuthRateLimit.consoleEntry`).\n\n## 2.0.0-dev.42\n\n### Aggiunte\n- Gestione dei flag di privilegio dalla console Accessi:\n - un admin pu\xF2 assegnare o togliere sia `FLGADMIN` sia `FLGSUPER`;\n - un superutente senza `FLGADMIN` pu\xF2 gestire solo `FLGSUPER`;\n - i flag sono impostabili in creazione (utente locale o SSO) e in modifica profilo.\n- Eliminazione utenti con due modalit\xE0:\n - soft delete (`delete-user`, `STAREG=DELETE`) per admin e superutenti;\n - eliminazione definitiva (`delete-user-permanent`, solo admin) che rimuove in transazione utente e record collegati.\n- Gestione completa dell'utente dalla console (admin): anagrafica estesa (cellulare, lingua, avatar, metadata JSON), GDPR, scadenza password, tutti i filtri (`FILTRI`) e **impostazione diretta della password** (`POST /api/accessi/user/set-password/:codiceUtente`), senza accesso al database.\n- Scritture utente idempotenti: `UTENTI_CONFIG` in `UPDATE OR INSERT ... MATCHING (CODUTE)`; i campi non inviati restano invariati.\n- Policy password moderna quando si imposta una password (reset, set-password admin, bootstrap): minimo 8 caratteri con maiuscola, minuscola, cifra e carattere speciale, senza spazi e non comune. In caso di violazione risposta 400 con `code: ACCESSI_WEAK_PASSWORD` e `details`. La policy **non** si applica al login, cos\xEC le password preesistenti deboli continuano a funzionare.\n\n### Correzioni\n- Il backend verifica i flag in base al ruolo dell'utente connesso (`ensurePrivilegeFlagChanges`): inviare un flag non consentito restituisce 403.\n\n## 2.0.0-dev.33\n\n### Cambiamenti\n- Rimosse le logiche applicative residue dallo schema Accessi:\n - `MENU_GRP.NOMECAMPO`\n - `UTENTI.ENABLEIA`\n - `UTENTI_CONFIG.PAGDEF`\n - `UTENTI.CELLUTE`\n- Telefono canonico: `UTENTI_CONFIG.CELLULARE` (allargato a `VARCHAR(30)`).\n- Migrazione automatica: copia `UTENTI.CELLUTE` \u2192 `UTENTI_CONFIG.CELLULARE`, poi `DROP` delle colonne obsolete.\n- Ruoli chiariti:\n - `FLGSUPER`: superutente, riceve **tutte** le abilitazioni al livello massimo (30) dopo il login; in console vede **solo** la sezione **Utenti**.\n - `FLGADMIN`: accede a **tutta** la console (catalogo, token, SSO, utenti) ma **non** influisce sulle abilitazioni.\n- Aggiunta la sezione **Changelog** in console (sotto la Wiki).\n\n### Note\n- `FILTRI` e `FILTRI_TIPO` restano invariati (piano di migrazione futuro).\n- I backend che usavano i campi rimossi devono gestirli in tabelle proprie.\n\n## 2.0.0-dev.32\n\n### Cambiamenti\n- Rimosso il supporto ai flag applicativi in `UTENTI_CONFIG`: `FLGMOP`, `FLGPIANA`, `FLGADDETTI`, `FLGOSPITI`, `FLGPIANARFID`, `FLGCONTA`, `FLGCUBI`, `FLGCICLPASS`, `FLGDIPENDENTI`, `FLGINVENTARI`, `CAUMOV`, `NUMMAC`, `RAGSOCCLI`.\n- Rinominata la colonna `FLGADMINCONFIG` in `FLGADMIN` (con copia dei valori e `DROP`).\n\n## 2.0.0-dev.31\n\n### Aggiunte\n- Esposizione dei servizi Accessi all'host Express (`getAccessiModuleServices`) per delegare login, SSO e token senza reimplementarli.\n\n### Correzioni\n- `UserService.getUsers`: filtri estesi (`codiceUtente[]`, `numRep[]`, `codDipendente`, `cellulare`, `tipFil`, `flagSuper`).\n\n## 2.0.0-dev.24\n\n### Cambiamenti (breaking)\n- Chiavi JWT derivate per scopo (`access`, `reset`, `2fa`) e claim `typ` obbligatorio: gli access token precedenti non sono pi\xF9 validi.\n- Endpoint Allegati protetti di default.\n- Pool di connessioni attivo di default (`poolSize` 5).\n\n### Aggiunte\n- Service token macchina-a-macchina (gestione, guard, console).\n- CRUD completo dei cataloghi dalla console Accessi.\n- Supporto Firebird 2.5 nel migrator e nei test di integrazione.\n";
|
|
1775
1789
|
|
|
1776
1790
|
// src/accessi-module/Console/help.ts
|
|
1777
1791
|
var p2 = (text) => ({ kind: "p", text });
|