emilsoftware-utilities 2.0.0-dev.37 → 2.0.0-dev.39
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-module/AccessiModule.d.ts +17 -1
- package/dist/accessi-module/AccessiModule.js +5 -6
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.css +46 -5
- package/dist/accessi-module/Console/console.js +74 -10
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/generated/accessiApi.d.ts +11 -1
- package/dist/accessi-module/Console/generated/accessiApi.js +11 -3
- package/dist/accessi-module/Console/generated/accessiApi.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/bootstrapAdminRequest.d.ts +17 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResultDto.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResultDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/bootstrapAdminResultDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +3 -0
- package/dist/accessi-module/Console/generated/model/index.js +3 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/index.html +14 -0
- package/dist/accessi-module/Console/wiki.js +3 -0
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AuthController.d.ts +5 -2
- package/dist/accessi-module/Controllers/AuthController.js +39 -3
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Dtos/AdminBootstrapDtos.d.ts +19 -0
- package/dist/accessi-module/Dtos/AdminBootstrapDtos.js +83 -0
- package/dist/accessi-module/Dtos/AdminBootstrapDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +1 -0
- package/dist/accessi-module/Dtos/index.js +1 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/AdminBootstrapService/AdminBootstrapService.d.ts +33 -0
- package/dist/accessi-module/Services/AdminBootstrapService/AdminBootstrapService.js +106 -0
- package/dist/accessi-module/Services/AdminBootstrapService/AdminBootstrapService.js.map +1 -0
- package/dist/accessi-module/index.d.ts +3 -0
- package/dist/accessi-module/index.js +10 -1
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/security/adminBootstrap.d.ts +8 -0
- package/dist/accessi-module/security/adminBootstrap.js +41 -0
- package/dist/accessi-module/security/adminBootstrap.js.map +1 -0
- package/dist/accessi-module/security/publicAuthRateLimit.d.ts +1 -1
- package/dist/accessi-module/security/publicAuthRateLimit.js +1 -0
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/startupLog.d.ts +6 -0
- package/dist/accessi-module/startupLog.js +25 -0
- package/dist/accessi-module/startupLog.js.map +1 -0
- package/dist/emilsoftware-utilities-2.0.0-dev.39.tgz +0 -0
- package/dist/initEmilsoftwareModule.js +2 -0
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/package.json +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.37.tgz +0 -0
|
@@ -56,6 +56,18 @@ export interface PublicAuthRateLimitOptions {
|
|
|
56
56
|
getUserByToken?: PublicAuthRateLimitRuleOptions;
|
|
57
57
|
twoFactorVerify?: PublicAuthRateLimitRuleOptions;
|
|
58
58
|
twoFactorResend?: PublicAuthRateLimitRuleOptions;
|
|
59
|
+
adminBootstrap?: PublicAuthRateLimitRuleOptions;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del
|
|
63
|
+
* processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.
|
|
64
|
+
* Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.
|
|
65
|
+
*/
|
|
66
|
+
export interface AdminBootstrapOptions {
|
|
67
|
+
/** Abilita il bootstrap admin. Default `false`. */
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
/** Crea l'utente come superutente oltre che admin. Default `true`. */
|
|
70
|
+
superUser?: boolean;
|
|
59
71
|
}
|
|
60
72
|
/** Controls the legacy public username/password registration endpoint. Disabled by default. */
|
|
61
73
|
export interface PublicRegistrationOptions {
|
|
@@ -119,7 +131,7 @@ export interface AccessiOptions {
|
|
|
119
131
|
/** Connessione Firebird alla base dati Accessi. */
|
|
120
132
|
databaseOptions: Options;
|
|
121
133
|
/**
|
|
122
|
-
* Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'
|
|
134
|
+
* Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'
|
|
123
135
|
*/
|
|
124
136
|
confirmationEmailUrl: string;
|
|
125
137
|
/**
|
|
@@ -157,6 +169,10 @@ export interface AccessiOptions {
|
|
|
157
169
|
serviceTokens?: ServiceTokenOptions;
|
|
158
170
|
/** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */
|
|
159
171
|
catalogScripts?: CatalogScriptsOptions;
|
|
172
|
+
/** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */
|
|
173
|
+
adminBootstrap?: AdminBootstrapOptions;
|
|
174
|
+
/** Base URL pubblica usata solo per loggare gli indirizzi (console, swagger, API). */
|
|
175
|
+
publicBaseUrl?: string;
|
|
160
176
|
}
|
|
161
177
|
export declare class AccessiModule {
|
|
162
178
|
/**
|
|
@@ -33,6 +33,7 @@ const ServiceTokenService_1 = require("./Services/ServiceTokenService/ServiceTok
|
|
|
33
33
|
const serviceTokenGuard_1 = require("./security/serviceTokenGuard");
|
|
34
34
|
const SchemaController_1 = require("./Controllers/SchemaController");
|
|
35
35
|
const SchemaExportService_1 = require("./Services/SchemaExportService/SchemaExportService");
|
|
36
|
+
const AdminBootstrapService_1 = require("./Services/AdminBootstrapService/AdminBootstrapService");
|
|
36
37
|
const emailConfiguration_1 = require("./security/emailConfiguration");
|
|
37
38
|
let AccessiModule = AccessiModule_1 = class AccessiModule {
|
|
38
39
|
/**
|
|
@@ -64,8 +65,7 @@ let AccessiModule = AccessiModule_1 = class AccessiModule {
|
|
|
64
65
|
AccessiDatabaseUpdater_1.AccessiDatabaseUpdater,
|
|
65
66
|
FederatedAuthService_1.FederatedAuthService,
|
|
66
67
|
ServiceTokenService_1.ServiceTokenService,
|
|
67
|
-
serviceTokenGuard_1.ServiceTokenGuard,
|
|
68
|
-
SchemaExportService_1.SchemaExportService
|
|
68
|
+
serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService
|
|
69
69
|
],
|
|
70
70
|
exports: [
|
|
71
71
|
'ACCESSI_OPTIONS',
|
|
@@ -79,8 +79,7 @@ let AccessiModule = AccessiModule_1 = class AccessiModule {
|
|
|
79
79
|
authenticateGen_1.AuthenticateGenService,
|
|
80
80
|
FederatedAuthService_1.FederatedAuthService,
|
|
81
81
|
ServiceTokenService_1.ServiceTokenService,
|
|
82
|
-
serviceTokenGuard_1.ServiceTokenGuard,
|
|
83
|
-
SchemaExportService_1.SchemaExportService
|
|
82
|
+
serviceTokenGuard_1.ServiceTokenGuard, SchemaExportService_1.SchemaExportService, AdminBootstrapService_1.AdminBootstrapService
|
|
84
83
|
],
|
|
85
84
|
};
|
|
86
85
|
}
|
|
@@ -101,8 +100,8 @@ exports.AccessiModule = AccessiModule = AccessiModule_1 = __decorate([
|
|
|
101
100
|
ServiceTokenController_1.ServiceTokenController,
|
|
102
101
|
SchemaController_1.SchemaController,
|
|
103
102
|
],
|
|
104
|
-
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],
|
|
105
|
-
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],
|
|
103
|
+
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],
|
|
104
|
+
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],
|
|
106
105
|
})
|
|
107
106
|
], AccessiModule);
|
|
108
107
|
//# sourceMappingURL=AccessiModule.js.map
|
|
@@ -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,qEAAkE;AAClE,4FAAyF;AACzF,sEAAsE;AAsL/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;gBACjB,yCAAmB;aACpB;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;gBACjB,yCAAmB;aACpB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAlDY,sCAAa;wBAAb,aAAa;IAjBzB,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,mCAAgB;SACjB;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,CAAC;QAC/Q,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,CAAC;KACpO,CAAC;GACW,aAAa,CAkDzB","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 { SchemaController } from './Controllers/SchemaController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\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 * 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}\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 SchemaController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService],\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 SchemaExportService\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 SchemaExportService\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,qEAAkE;AAClE,4FAAyF;AACzF,kGAA+F;AAC/F,sEAAsE;AAuM/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;IAjBzB,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,mCAAgB;SACjB;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 { 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 { SchemaController } from './Controllers/SchemaController';\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 /** 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}\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 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 /** 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, swagger, API). */\n publicBaseUrl?: string;\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 SchemaController,\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"]}
|
|
@@ -102,7 +102,7 @@ button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-
|
|
|
102
102
|
.card h1 { margin: 0 0 var(--s2); }
|
|
103
103
|
.card > p { margin: 0 0 var(--s5); color: var(--muted); }
|
|
104
104
|
.card form { gap: var(--s4); }
|
|
105
|
-
.card form button, .card > button { width: 100%; }
|
|
105
|
+
.card form > button, .card > button { width: 100%; }
|
|
106
106
|
.card > button { margin-top: var(--s3); }
|
|
107
107
|
|
|
108
108
|
#console { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); gap: var(--gutter); align-items: start; }
|
|
@@ -555,12 +555,48 @@ article h3 { margin-bottom: var(--s2); }
|
|
|
555
555
|
}
|
|
556
556
|
|
|
557
557
|
/* Aiuto contestuale: icona "i" e popover con la miniguida del campo */
|
|
558
|
-
|
|
559
|
-
.help-dot
|
|
560
|
-
|
|
558
|
+
/* Trigger "i": auto-contenuto, non eredita la forma dei bottoni applicativi. */
|
|
559
|
+
button.help-dot {
|
|
560
|
+
display: inline-flex;
|
|
561
|
+
align-items: center;
|
|
562
|
+
justify-content: center;
|
|
563
|
+
width: 1.125rem;
|
|
564
|
+
min-width: 1.125rem;
|
|
565
|
+
max-width: 1.125rem;
|
|
566
|
+
height: 1.125rem;
|
|
567
|
+
min-height: 1.125rem;
|
|
568
|
+
max-height: 1.125rem;
|
|
569
|
+
flex: 0 0 auto;
|
|
570
|
+
box-sizing: border-box;
|
|
571
|
+
margin: 0;
|
|
572
|
+
padding: 0;
|
|
573
|
+
border: 1px solid var(--line-strong);
|
|
574
|
+
border-radius: 50%;
|
|
575
|
+
color: var(--muted);
|
|
576
|
+
font-family: inherit;
|
|
577
|
+
font-size: .6875rem;
|
|
578
|
+
font-weight: 700;
|
|
579
|
+
line-height: 1;
|
|
580
|
+
background: var(--surface);
|
|
581
|
+
vertical-align: text-top;
|
|
582
|
+
cursor: pointer;
|
|
583
|
+
}
|
|
584
|
+
button.help-dot:hover,
|
|
585
|
+
button.help-dot:focus-visible { color: var(--brand-strong); border-color: var(--brand-line); background: var(--brand-soft); }
|
|
586
|
+
button.help-dot:focus-visible { outline: 2px solid var(--brand-line); outline-offset: 1px; }
|
|
587
|
+
|
|
588
|
+
/* Label "a blocchi" (caption + controllo): icona in alto a destra, senza rompere la griglia. */
|
|
589
|
+
label { position: relative; }
|
|
590
|
+
label:not(.check):not(.inline-field) > .help-dot { position: absolute; top: 0; right: 0; }
|
|
591
|
+
label:not(.check):not(.inline-field):has(> .help-dot) { padding-right: 1.625rem; }
|
|
592
|
+
/* Label flex: icona inline col testo. */
|
|
593
|
+
.check > .help-dot,
|
|
594
|
+
.inline-field > .help-dot { position: static; margin-left: var(--s1); }
|
|
595
|
+
.help-popover { position: fixed; z-index: 3000; width: min(460px, 94vw); max-height: 72vh; overflow: auto; overscroll-behavior: contain; padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); box-shadow: var(--shadow-md); }
|
|
596
|
+
.help-popover:focus { outline: none; }
|
|
561
597
|
.help-popover-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s3); }
|
|
562
598
|
.help-popover-head h4 { margin: 0; color: var(--ink); font-size: var(--fs-md); }
|
|
563
|
-
.help-close { width: 28px; min-height: 28px; padding: 0; font-size: var(--fs-lg); line-height: 1; }
|
|
599
|
+
.help-close { flex: 0 0 auto; width: 28px; min-width: 28px; min-height: 28px; padding: 0; font-size: var(--fs-lg); line-height: 1; }
|
|
564
600
|
.help-popover-body { display: grid; gap: var(--s3); }
|
|
565
601
|
.help-popover-body p { margin: 0; font-size: var(--fs-sm); line-height: 1.55; }
|
|
566
602
|
.help-popover-body ul, .help-popover-body ol { display: grid; gap: var(--s1); margin: 0; padding-left: var(--s4); font-size: var(--fs-sm); }
|
|
@@ -633,3 +669,8 @@ article h3 { margin-bottom: var(--s2); }
|
|
|
633
669
|
.sql-section { display: grid; gap: var(--s2); min-width: 0; }
|
|
634
670
|
.sql-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
|
|
635
671
|
.sql-section-head h3 { margin: 0; color: var(--ink); }
|
|
672
|
+
|
|
673
|
+
/* Bootstrap admin (schermata di login) */
|
|
674
|
+
.bootstrap-admin { margin-top: var(--s4); padding: var(--s3); border: 1px dashed var(--line); border-radius: var(--r-md); background: var(--surface-sunken); }
|
|
675
|
+
.bootstrap-admin summary { cursor: pointer; font-weight: 650; color: var(--ink-2); }
|
|
676
|
+
.bootstrap-admin form { display: grid; gap: var(--s2); margin-top: var(--s3); }
|
|
@@ -95,6 +95,21 @@ var resendTwoFactor = async (resendTwoFactorRequest, options) => {
|
|
|
95
95
|
}
|
|
96
96
|
);
|
|
97
97
|
};
|
|
98
|
+
var getBootstrapAdminUrl = () => {
|
|
99
|
+
return `/api/accessi/auth/bootstrap-admin`;
|
|
100
|
+
};
|
|
101
|
+
var bootstrapAdmin = async (bootstrapAdminRequest, options) => {
|
|
102
|
+
return accessiFetch(
|
|
103
|
+
getBootstrapAdminUrl(),
|
|
104
|
+
{
|
|
105
|
+
...options,
|
|
106
|
+
method: "POST",
|
|
107
|
+
body: JSON.stringify(
|
|
108
|
+
bootstrapAdminRequest
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
};
|
|
98
113
|
var getGetRolesUrl = () => {
|
|
99
114
|
return `/api/accessi/permission/roles`;
|
|
100
115
|
};
|
|
@@ -880,7 +895,9 @@ var WIKI_SECTIONS = [
|
|
|
880
895
|
["federatedAuthentication", "FederatedAuthenticationOptions", "no", `Abilita l'SSO generico.`],
|
|
881
896
|
["extensionFieldsOptions", "ExtensionFieldsOptions[]", "no", "Tabelle esterne allegate al profilo."],
|
|
882
897
|
["serviceTokens", "{ enabled, defaultTtlDays }", "no", "Token macchina-a-macchina, abilitati per impostazione predefinita."],
|
|
883
|
-
["catalogScripts", "{ enabled, folder, ... }", "no", "Catalog migrations SQL eseguite dopo la riconciliazione dello schema."]
|
|
898
|
+
["catalogScripts", "{ enabled, folder, ... }", "no", "Catalog migrations SQL eseguite dopo la riconciliazione dello schema."],
|
|
899
|
+
["adminBootstrap", "{ enabled, superUser }", "no", "Token casuale a ogni avvio per creare il primo admin dalla console."],
|
|
900
|
+
["publicBaseUrl", "string", "no", "Base URL usata solo per loggare console/swagger/API."]
|
|
884
901
|
]
|
|
885
902
|
),
|
|
886
903
|
good("ts", [
|
|
@@ -1375,7 +1392,8 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1375
1392
|
]),
|
|
1376
1393
|
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.`),
|
|
1377
1394
|
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.`),
|
|
1378
|
-
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).`)
|
|
1395
|
+
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).`),
|
|
1396
|
+
note("info", `Bootstrap admin`, `Con adminBootstrap.enabled il backend stampa a ogni avvio un token casuale (monouso, valido fino al riavvio). Nella schermata di login della console trovi "Crea utente admin": 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.`)
|
|
1379
1397
|
]
|
|
1380
1398
|
},
|
|
1381
1399
|
// -------------------------------------------------------------------------
|
|
@@ -2055,7 +2073,7 @@ function handleAction(action) {
|
|
|
2055
2073
|
void action().catch((error) => showNotice(errorMessage(error), true));
|
|
2056
2074
|
}
|
|
2057
2075
|
function render(markup) {
|
|
2058
|
-
closeHelp();
|
|
2076
|
+
closeHelp(false);
|
|
2059
2077
|
byId("view").innerHTML = markup;
|
|
2060
2078
|
}
|
|
2061
2079
|
function setActiveNavigation(view) {
|
|
@@ -3010,7 +3028,8 @@ function bindCopyButtons(root) {
|
|
|
3010
3028
|
});
|
|
3011
3029
|
}
|
|
3012
3030
|
function helpDot(key) {
|
|
3013
|
-
|
|
3031
|
+
const title = HELP[key]?.title ?? key;
|
|
3032
|
+
return `<button type="button" class="help-dot" data-help="${escapeHtml(key)}" aria-haspopup="dialog" aria-expanded="false" aria-controls="accessi-help-popover" aria-label="Informazioni: ${escapeHtml(title)}" title="Informazioni">i</button>`;
|
|
3014
3033
|
}
|
|
3015
3034
|
var helpPopover = null;
|
|
3016
3035
|
var helpAnchor = null;
|
|
@@ -3018,24 +3037,36 @@ function ensureHelpPopover() {
|
|
|
3018
3037
|
if (!helpPopover) {
|
|
3019
3038
|
helpPopover = document.createElement("div");
|
|
3020
3039
|
helpPopover.className = "help-popover";
|
|
3040
|
+
helpPopover.id = "accessi-help-popover";
|
|
3021
3041
|
helpPopover.hidden = true;
|
|
3022
3042
|
helpPopover.setAttribute("role", "dialog");
|
|
3043
|
+
helpPopover.setAttribute("aria-modal", "false");
|
|
3044
|
+
helpPopover.tabIndex = -1;
|
|
3023
3045
|
document.body.appendChild(helpPopover);
|
|
3024
3046
|
}
|
|
3025
3047
|
return helpPopover;
|
|
3026
3048
|
}
|
|
3027
|
-
function closeHelp() {
|
|
3028
|
-
if (helpPopover)
|
|
3049
|
+
function closeHelp(restoreFocus = true) {
|
|
3050
|
+
if (!helpPopover) return;
|
|
3051
|
+
const wasOpen = !helpPopover.hidden;
|
|
3052
|
+
helpPopover.hidden = true;
|
|
3053
|
+
const anchor = helpAnchor;
|
|
3054
|
+
if (anchor) anchor.setAttribute("aria-expanded", "false");
|
|
3029
3055
|
helpAnchor = null;
|
|
3056
|
+
if (restoreFocus && wasOpen && anchor && document.contains(anchor)) anchor.focus();
|
|
3030
3057
|
}
|
|
3031
3058
|
function positionHelp() {
|
|
3032
3059
|
if (!helpPopover || !helpAnchor || helpPopover.hidden) return;
|
|
3033
3060
|
const rect = helpAnchor.getBoundingClientRect();
|
|
3034
3061
|
const width = helpPopover.offsetWidth;
|
|
3035
3062
|
const height = helpPopover.offsetHeight;
|
|
3036
|
-
const
|
|
3063
|
+
const margin = 8;
|
|
3064
|
+
const left = Math.max(margin, Math.min(rect.right - width, window.innerWidth - width - margin));
|
|
3037
3065
|
let top = rect.bottom + 6;
|
|
3038
|
-
if (top + height > window.innerHeight -
|
|
3066
|
+
if (top + height > window.innerHeight - margin) {
|
|
3067
|
+
const above = rect.top - height - 6;
|
|
3068
|
+
top = above >= margin ? above : Math.max(margin, window.innerHeight - height - margin);
|
|
3069
|
+
}
|
|
3039
3070
|
helpPopover.style.left = `${left}px`;
|
|
3040
3071
|
helpPopover.style.top = `${top}px`;
|
|
3041
3072
|
}
|
|
@@ -3043,11 +3074,15 @@ function openHelp(anchor) {
|
|
|
3043
3074
|
const entry = HELP[anchor.dataset.help ?? ""];
|
|
3044
3075
|
if (!entry) return;
|
|
3045
3076
|
const popover = ensureHelpPopover();
|
|
3046
|
-
|
|
3077
|
+
if (helpAnchor && helpAnchor !== anchor) helpAnchor.setAttribute("aria-expanded", "false");
|
|
3078
|
+
popover.innerHTML = `<div class="help-popover-head"><h4 id="accessi-help-title">${escapeHtml(entry.title)}</h4><button type="button" class="help-close" data-help-close aria-label="Chiudi">×</button></div><div class="help-popover-body">${entry.blocks.map(renderWikiBlock).join("")}</div>`;
|
|
3079
|
+
popover.setAttribute("aria-labelledby", "accessi-help-title");
|
|
3047
3080
|
popover.hidden = false;
|
|
3048
3081
|
helpAnchor = anchor;
|
|
3082
|
+
anchor.setAttribute("aria-expanded", "true");
|
|
3049
3083
|
bindCopyButtons(popover);
|
|
3050
3084
|
positionHelp();
|
|
3085
|
+
(popover.querySelector(".help-close") ?? popover).focus();
|
|
3051
3086
|
}
|
|
3052
3087
|
function wikiIndexMarkup(selectedId) {
|
|
3053
3088
|
return wikiGroups().map(({ group, sections }) => `<div class="wiki-index-group"><span class="wiki-index-group-title">${escapeHtml(group)}</span><ul>${sections.map((section) => `<li><a href="#wiki-${escapeHtml(section.id)}" data-wiki="${escapeHtml(section.id)}"${section.id === selectedId ? ' aria-current="page"' : ""}>${escapeHtml(section.title)}</a></li>`).join("")}</ul></div>`).join("");
|
|
@@ -3204,6 +3239,31 @@ async function show(view) {
|
|
|
3204
3239
|
var loginForm = document.getElementById("login-form");
|
|
3205
3240
|
if (loginForm) loginForm.onsubmit = loginView;
|
|
3206
3241
|
byId("restart-login").onclick = resetLogin;
|
|
3242
|
+
var bootstrapAdminForm = document.getElementById("bootstrap-admin-form");
|
|
3243
|
+
if (bootstrapAdminForm) {
|
|
3244
|
+
bootstrapAdminForm.onsubmit = async (event) => {
|
|
3245
|
+
event.preventDefault();
|
|
3246
|
+
const status = document.getElementById("bootstrap-admin-status");
|
|
3247
|
+
try {
|
|
3248
|
+
if (status) status.textContent = "";
|
|
3249
|
+
const values = formValues(bootstrapAdminForm);
|
|
3250
|
+
const fields = new FormData(bootstrapAdminForm);
|
|
3251
|
+
const created = result(await bootstrapAdmin({
|
|
3252
|
+
token: values.token ?? "",
|
|
3253
|
+
email: values.email ?? "",
|
|
3254
|
+
nome: values.nome || void 0,
|
|
3255
|
+
cognome: values.cognome || void 0,
|
|
3256
|
+
password: values.password || void 0,
|
|
3257
|
+
superUser: fields.has("superUser")
|
|
3258
|
+
}));
|
|
3259
|
+
const generated = created.password ? ` Password generata (copiala ora): ${created.password}` : "";
|
|
3260
|
+
if (status) status.textContent = `Utente admin creato: ${created.email}.${generated} Ora accedi dal form principale.`;
|
|
3261
|
+
bootstrapAdminForm.reset();
|
|
3262
|
+
} catch (error) {
|
|
3263
|
+
if (status) status.textContent = error instanceof Error ? error.message : "Creazione non riuscita.";
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3207
3267
|
byId("two-factor-form").onsubmit = async (event) => {
|
|
3208
3268
|
event.preventDefault();
|
|
3209
3269
|
if (!pendingChallenge) return;
|
|
@@ -3250,7 +3310,11 @@ document.addEventListener("click", (event) => {
|
|
|
3250
3310
|
const dot = target.closest("[data-help]");
|
|
3251
3311
|
if (dot) {
|
|
3252
3312
|
event.preventDefault();
|
|
3253
|
-
|
|
3313
|
+
if (helpAnchor === dot && helpPopover && !helpPopover.hidden) {
|
|
3314
|
+
closeHelp();
|
|
3315
|
+
} else {
|
|
3316
|
+
openHelp(dot);
|
|
3317
|
+
}
|
|
3254
3318
|
return;
|
|
3255
3319
|
}
|
|
3256
3320
|
if (target.closest("[data-help-close]")) {
|