emilsoftware-utilities 2.0.0-dev.33 → 2.0.0-dev.35
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/README.MD +14 -0
- package/dist/accessi-module/AccessiModule.d.ts +24 -0
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.css +10 -0
- package/dist/accessi-module/Console/console.js +133 -11
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/generated/accessiApi.d.ts +2 -2
- package/dist/accessi-module/Console/generated/accessiApi.js.map +1 -1
- package/dist/accessi-module/Console/index.html +6 -0
- package/dist/accessi-module/Console/wiki.js +34 -3
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/ConfiguratorController.d.ts +1 -3
- package/dist/accessi-module/Controllers/ConfiguratorController.js +4 -17
- package/dist/accessi-module/Controllers/ConfiguratorController.js.map +1 -1
- package/dist/accessi-module/Controllers/FiltriController.js +4 -4
- package/dist/accessi-module/Controllers/FiltriController.js.map +1 -1
- package/dist/accessi-module/Controllers/PermissionController.js +14 -14
- package/dist/accessi-module/Controllers/PermissionController.js.map +1 -1
- package/dist/accessi-module/Controllers/ServiceTokenController.js +1 -1
- package/dist/accessi-module/Controllers/ServiceTokenController.js.map +1 -1
- package/dist/accessi-module/Controllers/UserController.js +8 -8
- package/dist/accessi-module/Controllers/UserController.js.map +1 -1
- package/dist/accessi-module/Services/UserService/UserService.d.ts +0 -2
- package/dist/accessi-module/Services/UserService/UserService.js +0 -16
- package/dist/accessi-module/Services/UserService/UserService.js.map +1 -1
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.d.ts +64 -0
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.js +288 -0
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.js.map +1 -0
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.d.ts +6 -0
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js +20 -1
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.d.ts +5 -0
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js +79 -0
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js.map +1 -0
- package/dist/accessi-module/database-updates/accessiSchema.d.ts +1 -1
- package/dist/accessi-module/database-updates/accessiSchema.js +10 -1
- package/dist/accessi-module/database-updates/accessiSchema.js.map +1 -1
- package/dist/accessi-module/database-updates/runAccessiCatalogMigrations.d.ts +1 -0
- package/dist/accessi-module/database-updates/runAccessiCatalogMigrations.js +57 -0
- package/dist/accessi-module/database-updates/runAccessiCatalogMigrations.js.map +1 -0
- package/dist/accessi-module/database-updates/runAccessiDbUpdate.js +2 -58
- package/dist/accessi-module/database-updates/runAccessiDbUpdate.js.map +1 -1
- package/dist/accessi-module/federated-auth/FederatedAuthController.js +15 -15
- package/dist/accessi-module/federated-auth/FederatedAuthController.js.map +1 -1
- package/dist/accessi-module/index.d.ts +3 -0
- package/dist/accessi-module/index.js +8 -1
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/security/accessControl.d.ts +11 -2
- package/dist/accessi-module/security/accessControl.js +28 -4
- package/dist/accessi-module/security/accessControl.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.35.tgz +0 -0
- package/package.json +6 -4
- package/dist/emilsoftware-utilities-2.0.0-dev.33.tgz +0 -0
package/README.MD
CHANGED
|
@@ -7,6 +7,20 @@ Documentazione completa del modulo Accessi, generata da `src/accessi-module/Cons
|
|
|
7
7
|
|
|
8
8
|
Rigenera entrambi con `npm run generate:accessi-wiki` (incluso in `npm run build`).
|
|
9
9
|
|
|
10
|
+
## Catalog migrations SQL
|
|
11
|
+
|
|
12
|
+
Per allineare menu, ruoli e cataloghi su più database, configura `catalogScripts` in `AccessiOptions`
|
|
13
|
+
(cartella con script `.sql` versionati nel backend) e usa le CLI:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ACCESSI_CATALOG_FOLDER=./db/accessi-catalog npm run db:catalog:accessi
|
|
17
|
+
ACCESSI_CATALOG_FOLDER=./db/accessi-catalog npm run db:catalog:accessi:check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Gli script sono applicati dopo la riconciliazione dello schema, una sola volta per database,
|
|
21
|
+
con tracking in `ACCESSI_CATALOG_SCRIPT` (nome + checksum). Dettagli nella Wiki, sezione
|
|
22
|
+
"Catalog migrations SQL".
|
|
23
|
+
|
|
10
24
|
---
|
|
11
25
|
|
|
12
26
|
Convenzioni per i Commit Message
|
|
@@ -69,6 +69,28 @@ export interface ServiceTokenOptions {
|
|
|
69
69
|
/** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */
|
|
70
70
|
defaultTtlDays?: number;
|
|
71
71
|
}
|
|
72
|
+
/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */
|
|
73
|
+
export type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';
|
|
74
|
+
/**
|
|
75
|
+
* Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel
|
|
76
|
+
* backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la
|
|
77
|
+
* riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,
|
|
78
|
+
* quindi viene applicato una sola volta per database (idempotenza lato DB).
|
|
79
|
+
*/
|
|
80
|
+
export interface CatalogScriptsOptions {
|
|
81
|
+
/** Abilita l'esecuzione automatica al bootstrap. Default `false`. */
|
|
82
|
+
enabled?: boolean;
|
|
83
|
+
/** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */
|
|
84
|
+
folder: string;
|
|
85
|
+
/** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */
|
|
86
|
+
onChecksumMismatch?: CatalogScriptChecksumPolicy;
|
|
87
|
+
/** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */
|
|
88
|
+
stopOnError?: boolean;
|
|
89
|
+
/** Globi/estensioni inclusi. Default: tutti i `.sql`. */
|
|
90
|
+
include?: string[];
|
|
91
|
+
/** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */
|
|
92
|
+
maxScriptsPerRun?: number;
|
|
93
|
+
}
|
|
72
94
|
/**
|
|
73
95
|
* Enables Accessi's provider-agnostic federated identity capability.
|
|
74
96
|
*
|
|
@@ -128,6 +150,8 @@ export interface AccessiOptions {
|
|
|
128
150
|
extensionFieldsOptions?: ExtensionFieldsOptions[];
|
|
129
151
|
/** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */
|
|
130
152
|
serviceTokens?: ServiceTokenOptions;
|
|
153
|
+
/** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */
|
|
154
|
+
catalogScripts?: CatalogScriptsOptions;
|
|
131
155
|
}
|
|
132
156
|
export declare class AccessiModule {
|
|
133
157
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAC/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,4FAAyF;AACzF,oEAAiE;AACjE,sEAAsE;AAsJ/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;aAClB;YACD,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;aAClB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAhDY,sCAAa;wBAAb,aAAa;IAhBzB,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;SACvB;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,CAAC;QAC1P,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,CAAC;KAC/M,CAAC;GACW,aAAa,CAgDzB","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 { 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 { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\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 /** 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}\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/**\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}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ServiceTokenController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard],\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\n ],\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\n ],\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAC/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,4FAAyF;AACzF,oEAAiE;AACjE,sEAAsE;AAgL/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;aAClB;YACD,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;aAClB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAhDY,sCAAa;wBAAb,aAAa;IAhBzB,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;SACvB;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,CAAC;QAC1P,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,CAAC;KAC/M,CAAC;GACW,aAAa,CAgDzB","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 { 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 { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\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 /** 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}\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 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\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}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ServiceTokenController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard],\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\n ],\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\n ],\n };\n }\n}\n"]}
|
|
@@ -616,3 +616,13 @@ article h3 { margin-bottom: var(--s2); }
|
|
|
616
616
|
@media (prefers-reduced-motion: reduce) {
|
|
617
617
|
*, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
|
|
618
618
|
}
|
|
619
|
+
|
|
620
|
+
/* Changelog / markdown body */
|
|
621
|
+
.markdown-body h1 { margin: 0 0 var(--s3); font-size: 1.55rem; color: var(--ink); }
|
|
622
|
+
.markdown-body h2 { margin: var(--s5) 0 var(--s2); padding-top: var(--s3); border-top: 1px solid var(--line); font-size: 1.2rem; color: var(--ink); }
|
|
623
|
+
.markdown-body h3 { margin: var(--s4) 0 var(--s2); font-size: 1rem; color: var(--ink-2); }
|
|
624
|
+
.markdown-body h4 { margin: var(--s3) 0 var(--s1); font-size: .95rem; color: var(--ink-2); }
|
|
625
|
+
.markdown-body strong { color: var(--ink); }
|
|
626
|
+
.markdown-body code { padding: 1px 5px; border-radius: var(--r-sm); color: var(--brand-strong); background: var(--brand-soft); font-family: var(--font-mono); font-size: .92em; }
|
|
627
|
+
.markdown-code { margin: 0; padding: var(--s4); overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
|
|
628
|
+
.markdown-code code { padding: 0; background: transparent; color: var(--ink); white-space: pre; }
|
|
@@ -867,7 +867,8 @@ var WIKI_SECTIONS = [
|
|
|
867
867
|
["publicRegistration", "{ enabled }", "no", "Registrazione pubblica: disattivata per impostazione predefinita."],
|
|
868
868
|
["federatedAuthentication", "FederatedAuthenticationOptions", "no", `Abilita l'SSO generico.`],
|
|
869
869
|
["extensionFieldsOptions", "ExtensionFieldsOptions[]", "no", "Tabelle esterne allegate al profilo."],
|
|
870
|
-
["serviceTokens", "{ enabled, defaultTtlDays }", "no", "Token macchina-a-macchina, abilitati per impostazione predefinita."]
|
|
870
|
+
["serviceTokens", "{ enabled, defaultTtlDays }", "no", "Token macchina-a-macchina, abilitati per impostazione predefinita."],
|
|
871
|
+
["catalogScripts", "{ enabled, folder, ... }", "no", "Catalog migrations SQL eseguite dopo la riconciliazione dello schema."]
|
|
871
872
|
]
|
|
872
873
|
),
|
|
873
874
|
good("ts", [
|
|
@@ -925,7 +926,7 @@ var WIKI_SECTIONS = [
|
|
|
925
926
|
`RUOLI, MENU_GRP, MENU_TIPI, MENU, ABILITAZIONI, RUOLI_MNU, UTENTI_RUOLI`,
|
|
926
927
|
`FILTRI, FILTRI_TIPO`,
|
|
927
928
|
`SSO_PROVIDER, UTENTI_IDENTITA_EXT`,
|
|
928
|
-
`ACCESSI_2FA, ACCESSI_SERVICE_TOKEN`
|
|
929
|
+
`ACCESSI_2FA, ACCESSI_SERVICE_TOKEN, ACCESSI_CATALOG_SCRIPT`
|
|
929
930
|
]),
|
|
930
931
|
code("bash", `npm run db:update:accessi # riconcilia lo schema
|
|
931
932
|
npm run db:check:accessi # verifica senza modificare`, "CLI schema"),
|
|
@@ -933,6 +934,37 @@ npm run db:check:accessi # verifica senza modificare`, "CLI schema"),
|
|
|
933
934
|
]
|
|
934
935
|
},
|
|
935
936
|
// -------------------------------------------------------------------------
|
|
937
|
+
{
|
|
938
|
+
id: "catalog-migrations",
|
|
939
|
+
group: "Configurazione",
|
|
940
|
+
title: "Catalog migrations SQL",
|
|
941
|
+
summary: "Allinea menu, ruoli e cataloghi su piu database in modo idempotente.",
|
|
942
|
+
blocks: [
|
|
943
|
+
p(`Gli script SQL applicativi (menu, ruoli, tipi, cataloghi) restano nel repository del backend ospitante e Accessi li esegue dopo la riconciliazione dello schema. Ogni script viene tracciato nella tabella ACCESSI_CATALOG_SCRIPT (nome + checksum), quindi viene applicato una sola volta per database.`),
|
|
944
|
+
h(`Configurazione`),
|
|
945
|
+
good("ts", [
|
|
946
|
+
"catalogScripts: {",
|
|
947
|
+
" enabled: true,",
|
|
948
|
+
" folder: './db/accessi-catalog', // versionata nel repo del backend",
|
|
949
|
+
" onChecksumMismatch: 'error', // 'error' (default) | 'warn' | 'reapply'",
|
|
950
|
+
" stopOnError: true,",
|
|
951
|
+
"}"
|
|
952
|
+
].join("\n"), "AccessiOptions"),
|
|
953
|
+
list([
|
|
954
|
+
"Gli script sono ordinati per percorso (usa prefissi numerici: 0001_, 0002_, ...).",
|
|
955
|
+
"Devono essere idempotenti e ripetibili: UPDATE OR INSERT ... MATCHING, MERGE, DELETE+INSERT mirati.",
|
|
956
|
+
"Non includere utenti: le catalog migrations allineano solo catalogo e configurazione.",
|
|
957
|
+
"Supportati SET TERM, stringhe e commenti; nessuna semantica SQL viene interpretata."
|
|
958
|
+
]),
|
|
959
|
+
code("bash", `# Applica (schema + catalog migrations) su un database
|
|
960
|
+
ACCESSI_CATALOG_FOLDER=./db/accessi-catalog npm run db:catalog:accessi
|
|
961
|
+
|
|
962
|
+
# Elenca solo quelle da applicare / modificate
|
|
963
|
+
ACCESSI_CATALOG_FOLDER=./db/accessi-catalog npm run db:catalog:accessi:check`, "CLI catalog migrations"),
|
|
964
|
+
note("info", `Idempotenza`, `Uno script gia applicato con lo stesso checksum viene saltato. Se il file cambia dopo l'applicazione, con policy error il run si interrompe: non modificare uno script applicato, aggiungine uno nuovo.`)
|
|
965
|
+
]
|
|
966
|
+
},
|
|
967
|
+
// -------------------------------------------------------------------------
|
|
936
968
|
{
|
|
937
969
|
id: "login",
|
|
938
970
|
group: "Autenticazione",
|
|
@@ -1315,16 +1347,19 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1315
1347
|
title: "Console amministrativa",
|
|
1316
1348
|
summary: "Accesso, sezioni e che cosa si pu\xF2 fare.",
|
|
1317
1349
|
blocks: [
|
|
1318
|
-
p(`La console \xE8 servita dal modulo su /api/accessi/console
|
|
1350
|
+
p(`La console \xE8 servita dal modulo su /api/accessi/console. Non ha stato proprio: ogni azione chiama le API protette con il JWT dell'utente connesso.`),
|
|
1319
1351
|
list([
|
|
1320
1352
|
`Utenti: elenco, creazione locale o SSO, profilo, ruoli, grant diretti, stato, 2FA.`,
|
|
1321
1353
|
`Ruoli e grant: CRUD dei ruoli con l'albero delle abilitazioni.`,
|
|
1322
1354
|
`Menu e gruppi: CRUD di gruppi, menu e tipi menu.`,
|
|
1323
1355
|
`Filtri: filtri utente e tipi filtro.`,
|
|
1324
1356
|
`Token di servizio: creazione, rotazione, revoca.`,
|
|
1325
|
-
`SSO: provider e identit\xE0
|
|
1357
|
+
`SSO: provider e identit\xE0.`,
|
|
1358
|
+
`Wiki e Changelog: documentazione e novit\xE0 della libreria.`
|
|
1326
1359
|
]),
|
|
1327
|
-
note("info", `
|
|
1360
|
+
note("info", `Superutente (FLGSUPER)`, `Riceve TUTTE le abilitazioni al livello massimo (30) dopo il login. In console vede solo la sezione Utenti e gestisce utenti, ruoli e grant.`),
|
|
1361
|
+
note("info", `Admin (FLGADMIN)`, `Accede a tutta la console (catalogo, token, SSO, utenti) ma NON conferisce abilitazioni: i menu restano quelli assegnati via ABILITAZIONI/RUOLI_MNU.`),
|
|
1362
|
+
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).`)
|
|
1328
1363
|
]
|
|
1329
1364
|
},
|
|
1330
1365
|
// -------------------------------------------------------------------------
|
|
@@ -1463,6 +1498,9 @@ function buildAiDigest() {
|
|
|
1463
1498
|
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
1464
1499
|
}
|
|
1465
1500
|
|
|
1501
|
+
// src/accessi-module/Console/changelog.md
|
|
1502
|
+
var changelog_default = "# Changelog Accessi\n\nNovit\xE0 e modifiche rilevanti della libreria `emilsoftware-utilities` (modulo Accessi).\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";
|
|
1503
|
+
|
|
1466
1504
|
// src/accessi-module/Console/help.ts
|
|
1467
1505
|
var p2 = (text) => ({ kind: "p", text });
|
|
1468
1506
|
var list2 = (items) => ({ kind: "list", items });
|
|
@@ -1833,7 +1871,8 @@ var routeSegment = {
|
|
|
1833
1871
|
ssoProviders: "sso/provider",
|
|
1834
1872
|
ssoUsers: "sso/utenti",
|
|
1835
1873
|
tokens: "token-di-servizio",
|
|
1836
|
-
wiki: "wiki"
|
|
1874
|
+
wiki: "wiki",
|
|
1875
|
+
changelog: "changelog"
|
|
1837
1876
|
};
|
|
1838
1877
|
var routeView = Object.fromEntries(Object.entries(routeSegment).map(([view, segment]) => [segment, view]));
|
|
1839
1878
|
var parentDefaultView = {
|
|
@@ -2022,6 +2061,10 @@ function viewFromLocation() {
|
|
|
2022
2061
|
return routeView[decoded] ?? parentDefaultView[decoded] ?? "users";
|
|
2023
2062
|
}
|
|
2024
2063
|
async function navigate(view, replace = false) {
|
|
2064
|
+
if (!isViewAllowed(view)) {
|
|
2065
|
+
view = "users";
|
|
2066
|
+
replace = true;
|
|
2067
|
+
}
|
|
2025
2068
|
const destination = routePath(view);
|
|
2026
2069
|
if (window.location.pathname !== destination) {
|
|
2027
2070
|
window.history[replace ? "replaceState" : "pushState"]({ view }, "", destination);
|
|
@@ -2029,8 +2072,26 @@ async function navigate(view, replace = false) {
|
|
|
2029
2072
|
if (view === "users") usersPage = 0;
|
|
2030
2073
|
await show(view);
|
|
2031
2074
|
}
|
|
2032
|
-
function
|
|
2033
|
-
if (!currentUser?.flagSuper
|
|
2075
|
+
function requireConsoleAccess() {
|
|
2076
|
+
if (!currentUser?.flagSuper && !currentUser?.flagAdmin) {
|
|
2077
|
+
throw new Error("La console richiede un superutente o un admin Accessi.");
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
function isViewAllowed(view) {
|
|
2081
|
+
if (!currentUser) return false;
|
|
2082
|
+
if (currentUser.flagAdmin) return true;
|
|
2083
|
+
return view === "users";
|
|
2084
|
+
}
|
|
2085
|
+
function applyRoleNavigation() {
|
|
2086
|
+
document.querySelectorAll("#nav [data-view]").forEach((link) => {
|
|
2087
|
+
const view = link.dataset.view;
|
|
2088
|
+
const item = link.closest("li") ?? link;
|
|
2089
|
+
item.hidden = !isViewAllowed(view);
|
|
2090
|
+
});
|
|
2091
|
+
document.querySelectorAll("#nav details[data-nav-group]").forEach((branch) => {
|
|
2092
|
+
const hasVisible = Array.from(branch.querySelectorAll("[data-view]")).some((link) => !link.closest("li").hidden);
|
|
2093
|
+
branch.hidden = !hasVisible;
|
|
2094
|
+
});
|
|
2034
2095
|
}
|
|
2035
2096
|
function formValues(form) {
|
|
2036
2097
|
return Object.fromEntries(new FormData(form).entries());
|
|
@@ -2234,9 +2295,11 @@ async function bootstrap() {
|
|
|
2234
2295
|
if (!token) throw new Error("Inserisci le credenziali amministrative.");
|
|
2235
2296
|
const payload = result(await getUserByToken({ token }));
|
|
2236
2297
|
currentUser = payload.userData;
|
|
2237
|
-
|
|
2298
|
+
requireConsoleAccess();
|
|
2299
|
+
applyRoleNavigation();
|
|
2238
2300
|
await detectFederatedAuthentication();
|
|
2239
|
-
|
|
2301
|
+
const roleLabel = currentUser.flagSuper && currentUser.flagAdmin ? "super + admin" : currentUser.flagAdmin ? "admin" : "superutente";
|
|
2302
|
+
byId("who").textContent = `${currentUser.email} - ${roleLabel}`;
|
|
2240
2303
|
byId("sso-navigation").hidden = !federatedAuthenticationAvailable;
|
|
2241
2304
|
finishBoot("console");
|
|
2242
2305
|
await navigate(viewFromLocation(), window.location.pathname === consoleBasePath);
|
|
@@ -3000,6 +3063,64 @@ async function showWiki(sectionId) {
|
|
|
3000
3063
|
showNotice("Documentazione per AI copiata negli appunti.");
|
|
3001
3064
|
});
|
|
3002
3065
|
}
|
|
3066
|
+
function inlineMarkdown(text) {
|
|
3067
|
+
return escapeHtml(text).replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
3068
|
+
}
|
|
3069
|
+
function renderMarkdown(markdown) {
|
|
3070
|
+
const lines = markdown.replace(/\r\n/g, "\n").split("\n");
|
|
3071
|
+
const html = [];
|
|
3072
|
+
let inList = false;
|
|
3073
|
+
let inCode = false;
|
|
3074
|
+
const closeList = () => {
|
|
3075
|
+
if (inList) {
|
|
3076
|
+
html.push("</ul>");
|
|
3077
|
+
inList = false;
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
3080
|
+
for (const line of lines) {
|
|
3081
|
+
if (line.startsWith("```")) {
|
|
3082
|
+
closeList();
|
|
3083
|
+
html.push(inCode ? "</code></pre>" : '<pre class="markdown-code"><code>');
|
|
3084
|
+
inCode = !inCode;
|
|
3085
|
+
continue;
|
|
3086
|
+
}
|
|
3087
|
+
if (inCode) {
|
|
3088
|
+
html.push(escapeHtml(line));
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
const heading = /^(#{1,4})\s+(.*)$/.exec(line);
|
|
3092
|
+
if (heading) {
|
|
3093
|
+
closeList();
|
|
3094
|
+
const level = (heading[1] ?? "").length;
|
|
3095
|
+
html.push(`<h${level}>${inlineMarkdown(heading[2] ?? "")}</h${level}>`);
|
|
3096
|
+
continue;
|
|
3097
|
+
}
|
|
3098
|
+
const bullet = /^\s*[-*]\s+(.*)$/.exec(line);
|
|
3099
|
+
if (bullet) {
|
|
3100
|
+
if (!inList) {
|
|
3101
|
+
html.push("<ul>");
|
|
3102
|
+
inList = true;
|
|
3103
|
+
}
|
|
3104
|
+
html.push(`<li>${inlineMarkdown(bullet[1] ?? "")}</li>`);
|
|
3105
|
+
continue;
|
|
3106
|
+
}
|
|
3107
|
+
if (line.trim() === "") {
|
|
3108
|
+
closeList();
|
|
3109
|
+
continue;
|
|
3110
|
+
}
|
|
3111
|
+
closeList();
|
|
3112
|
+
html.push(`<p>${inlineMarkdown(line)}</p>`);
|
|
3113
|
+
}
|
|
3114
|
+
if (inCode) html.push("</code></pre>");
|
|
3115
|
+
closeList();
|
|
3116
|
+
return html.join("");
|
|
3117
|
+
}
|
|
3118
|
+
async function showChangelog() {
|
|
3119
|
+
render(`<div class="wiki"><article class="wiki-content markdown-body">
|
|
3120
|
+
<header class="wiki-section-head"><h2>Changelog</h2><p>Novita e modifiche rilevanti del modulo Accessi.</p></header>
|
|
3121
|
+
${renderMarkdown(changelog_default)}
|
|
3122
|
+
</article></div>`);
|
|
3123
|
+
}
|
|
3003
3124
|
async function show(view) {
|
|
3004
3125
|
try {
|
|
3005
3126
|
showNotice("");
|
|
@@ -3014,7 +3135,8 @@ async function show(view) {
|
|
|
3014
3135
|
ssoProviders: showSsoProviders,
|
|
3015
3136
|
ssoUsers: showSsoUsers,
|
|
3016
3137
|
tokens: showServiceTokens,
|
|
3017
|
-
wiki: showWiki
|
|
3138
|
+
wiki: showWiki,
|
|
3139
|
+
changelog: showChangelog
|
|
3018
3140
|
};
|
|
3019
3141
|
setActiveNavigation(view);
|
|
3020
3142
|
const renderView = views[view];
|