emilsoftware-utilities 2.0.0-dev.75 → 2.0.0-dev.76
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 +2 -1
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.js +2 -2
- package/dist/accessi-module/Console/index.html +1 -1
- package/dist/accessi-module/Console/wiki.js +2 -2
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.d.ts +5 -3
- package/dist/accessi-module/Controllers/AccessiConsoleController.js +39 -12
- package/dist/accessi-module/Controllers/AccessiConsoleController.js.map +1 -1
- package/dist/accessi-module/index.d.ts +2 -0
- package/dist/accessi-module/index.js +15 -14
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/security/securityHeaders.d.ts +89 -0
- package/dist/accessi-module/security/securityHeaders.js +155 -0
- package/dist/accessi-module/security/securityHeaders.js.map +1 -0
- package/dist/emilsoftware-utilities-2.0.0-dev.76.tgz +0 -0
- package/dist/initEmilsoftwareModule.js +6 -11
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/docs/security-headers.md +151 -0
- package/package.json +3 -3
- package/dist/emilsoftware-utilities-2.0.0-dev.75.tgz +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessiConsoleController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/AccessiConsoleController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAqE;AACrE,6CAAuD;AAEvD,2BAAkC;AAClC,+BAA4B;
|
|
1
|
+
{"version":3,"file":"AccessiConsoleController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/AccessiConsoleController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Controller, Get, Inject, Param, Res } from '@nestjs/common';\nimport { ApiExcludeController } from '@nestjs/swagger';\nimport { Response } from 'express';\nimport { randomBytes } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport type { AccessiOptions } from '../AccessiModule';\nimport {\n applyAccessiContentSecurityPolicy,\n resolveAccessiSecurityHeaders,\n} from '../security/securityHeaders';\n\n/** Serves the framework-free administrative console bundled with Accessi. API authorization remains on each API endpoint. */\n@ApiExcludeController()\n@Controller('accessi/console')\nexport class AccessiConsoleController {\n private htmlCache?: { baseUrl: string | undefined; content: string };\n\n constructor(@Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions) {}\n\n private indexHtml(): string {\n const baseUrl = this.options.consoleApiBaseUrl?.replace(/\\/+$/, '');\n if (this.htmlCache && this.htmlCache.baseUrl === baseUrl) return this.htmlCache.content;\n\n const marker = baseUrl\n ? `<script nonce=\"__ACCESSI_CSP_NONCE__\">window.__ACCESSI_API_BASE_URL__=${JSON.stringify(baseUrl)};</script>`\n : '';\n const content = readFileSync(join(__dirname, '..', 'Console', 'index.html'), 'utf8')\n .replace('</head>', `${marker}</head>`);\n this.htmlCache = { baseUrl, content };\n return content;\n }\n\n /** Origini raggiungibili dalla console: l'API puo stare su un dominio diverso. */\n private consoleConnectSrc(): string[] {\n const baseUrl = this.options.consoleApiBaseUrl?.replace(/\\/+$/, '');\n if (!baseUrl) return [];\n try {\n const url = new URL(baseUrl);\n return [`${url.protocol}//${url.host}`];\n } catch {\n return [];\n }\n }\n\n @Get()\n index(@Res() res: Response) {\n const security = resolveAccessiSecurityHeaders(this.options.http?.securityHeaders);\n res.setHeader('Cache-Control', security?.cacheControl || 'no-store, max-age=0');\n res.setHeader('Referrer-Policy', security?.referrerPolicy || 'no-referrer');\n res.setHeader('X-Content-Type-Options', 'nosniff');\n if (security) {\n if (security.frameOptions) res.setHeader('X-Frame-Options', security.frameOptions);\n if (security.permissionsPolicy) res.setHeader('Permissions-Policy', security.permissionsPolicy);\n }\n\n // Il nonce cambia a ogni risposta: la shell HTML non puo essere cacheata con il valore incorporato.\n const nonce = security?.contentSecurityPolicy ? randomBytes(16).toString('base64') : '';\n if (security) {\n applyAccessiContentSecurityPolicy(res, security, 'console', {\n ...(nonce ? { nonce } : {}),\n connectSrc: this.consoleConnectSrc(),\n });\n }\n\n const html = this.indexHtml().split('__ACCESSI_CSP_NONCE__').join(nonce);\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n return res.send(html);\n }\n\n /**\n * Percorsi SPA ammessi. Deve restare allineato a `routeSegment` (e ai padri dei\n * sottomenu) in Console/console.ts, altrimenti i deep link restituiscono 404.\n */\n private static readonly allowedViews = new Set([\n 'utenti',\n 'ruoli-e-grant',\n 'menu-e-gruppi',\n 'menu-e-gruppi/gruppi',\n 'menu-e-gruppi/menu',\n 'menu-e-gruppi/tipi-menu',\n 'filtri',\n 'filtri/utente',\n 'filtri/tipi',\n 'sso',\n 'sso/provider',\n 'sso/utenti',\n 'token-di-servizio',\n 'wiki',\n ]);\n\n // Le route statiche vanno dichiarate prima di `:view/:sub`, che altrimenti\n // catturerebbe `assets/<file>` e restituirebbe 404 per CSS e bundle.\n @Get('assets/:file')\n asset(@Param('file') file: string, @Res() res: Response) {\n const allowed = new Set(['console.css', 'console.js']);\n if (!allowed.has(file)) return res.status(404).end();\n // Keep the SPA shell, styles and bundle on the same deployed revision.\n res.setHeader('Cache-Control', 'no-store, max-age=0');\n return res.sendFile(join(__dirname, '..', 'Console', file));\n }\n\n /**\n * Serves the SPA shell for the supported console sections, allowing direct\n * navigation, bookmarks and browser back/forward without server-side state.\n */\n @Get(':view')\n section(@Param('view') view: string, @Res() res: Response) {\n if (!AccessiConsoleController.allowedViews.has(view)) return res.status(404).end();\n return this.index(res);\n }\n\n /** Serves the SPA shell for nested sections (menu, filtri, SSO). */\n @Get(':view/:sub')\n subsection(@Param('view') view: string, @Param('sub') sub: string, @Res() res: Response) {\n if (!AccessiConsoleController.allowedViews.has(`${view}/${sub}`)) return res.status(404).end();\n return this.index(res);\n }\n}\n"]}
|
|
@@ -60,6 +60,8 @@ export { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredErro
|
|
|
60
60
|
export { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';
|
|
61
61
|
export { buildAccessiJwks, createAccessiJwksHandler, getAccessiJwksPath, setupAccessiJwks } from './security/jwks';
|
|
62
62
|
export type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';
|
|
63
|
+
export { applyAccessiBaseSecurityHeaders, applyAccessiContentSecurityPolicy, buildAccessiContentSecurityPolicy, createAccessiSecurityHeadersMiddleware, resolveAccessiSecurityHeaders } from './security/securityHeaders';
|
|
64
|
+
export type { AccessiCspDirectives, AccessiCspOptions, AccessiCspSurface, AccessiSecurityHeadersOptions, AccessiSecurityHeadersSetting, ResolvedAccessiCsp, ResolvedAccessiSecurityHeaders } from './security/securityHeaders';
|
|
63
65
|
export { getAccessiAccessTokenSigningConfig, getAccessiAccessTokenVerificationConfig, getAccessiRefreshTokenSigningConfig, getAccessiRefreshTokenVerificationConfig, resolveAccessiVerificationKeys, verifyAccessiJwt } from './security/jwtTokenOptions';
|
|
64
66
|
export type { AccessiJwtVerificationConfig, AccessiUnknownKeyIdEvent } from './security/jwtTokenOptions';
|
|
65
67
|
export { FederatedAuthService } from './federated-auth/FederatedAuthService';
|
|
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.isValidAdminBootstrapToken = exports.clearAdminBootstrapToken = exports.getAdminBootstrapToken = exports.getOrCreateAdminBootstrapToken = exports.AdminBootstrapService = exports.SchemaExportService = exports.ServiceTokenService = exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.leadingStatementKeyword = exports.analyzeCatalogScript = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.revokeAccessiAccessTokenIfConfigured = exports.revokeAccessiAccessToken = exports.isAccessiAccessTokenRevoked = exports.getAccessTokenRevocationStore = exports.createRedisAccessTokenRevocationStore = exports.createMemoryAccessTokenRevocationStore = exports.revokeRefreshTokenFamily = exports.isRefreshTokenFamilyRevoked = exports.getRefreshTokenRotationStore = exports.consumeRefreshToken = exports.createRedisRefreshTokenRotationStore = exports.createMemoryRefreshTokenRotationStore = exports.getSessionRevocationStore = exports.isAccessiTokenRevoked = exports.revokeAccessiUserSessionsIfConfigured = exports.revokeAccessiUserSessions = exports.createRedisSessionRevocationStore = exports.createMemorySessionRevocationStore = exports.auditAccessi = exports.validateAccessiOptions = exports.assertValidAccessiOptions = exports.createAccessiEdgeRateLimitMiddleware = exports.getDefaultRateLimitStore = exports.createRedisRateLimitStore = exports.createMemoryRateLimitStore = exports.getDefaultConsoleEntryStore = exports.createRedisConsoleEntryStore = exports.createMemoryConsoleEntryStore = exports.AccessiDatabaseUpdater = exports.FederatedAuthExchangeController = exports.AccessiIntrospectionController = exports.AccessiModule = void 0;
|
|
30
|
-
exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.verifyAccessiJwt = exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = void 0;
|
|
30
|
+
exports.createAccessiHealthModule = exports.readinessHttpStatus = exports.createAccessiLiveReport = exports.collectAccessiHealthStores = exports.checkAccessiDatabase = exports.checkAccessiReadiness = exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.verifyAccessiJwt = exports.resolveAccessiVerificationKeys = exports.getAccessiRefreshTokenVerificationConfig = exports.getAccessiRefreshTokenSigningConfig = exports.getAccessiAccessTokenVerificationConfig = exports.getAccessiAccessTokenSigningConfig = exports.resolveAccessiSecurityHeaders = exports.createAccessiSecurityHeadersMiddleware = exports.buildAccessiContentSecurityPolicy = exports.applyAccessiContentSecurityPolicy = exports.applyAccessiBaseSecurityHeaders = exports.setupAccessiJwks = exports.getAccessiJwksPath = exports.createAccessiJwksHandler = exports.buildAccessiJwks = exports.LOGIN_AS_QUERY_PARAM = exports.buildLoginAsUrl = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = void 0;
|
|
31
31
|
exports.initializeAccessiModule = initializeAccessiModule;
|
|
32
32
|
const express_1 = __importDefault(require("express"));
|
|
33
33
|
const core_1 = require("@nestjs/core");
|
|
@@ -44,6 +44,7 @@ const AccessiHttpExceptionFilter_1 = require("./security/AccessiHttpExceptionFil
|
|
|
44
44
|
const emailConfiguration_1 = require("./security/emailConfiguration");
|
|
45
45
|
const jwks_1 = require("./security/jwks");
|
|
46
46
|
const edgeRateLimit_1 = require("./security/edgeRateLimit");
|
|
47
|
+
const securityHeaders_1 = require("./security/securityHeaders");
|
|
47
48
|
function describeDatabaseTarget(options) {
|
|
48
49
|
var _a, _b, _c, _d;
|
|
49
50
|
const dbOptions = options.databaseOptions;
|
|
@@ -64,7 +65,7 @@ function describeDatabaseTarget(options) {
|
|
|
64
65
|
*/
|
|
65
66
|
function initializeAccessiModule(app, options) {
|
|
66
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
-
var _a, _b, _c, _d, _e, _f;
|
|
68
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
68
69
|
// Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.
|
|
69
70
|
(0, emailConfiguration_1.assertEmailConfigured)(options);
|
|
70
71
|
const logger = new Logger_1.Logger("initializeAccessiModule");
|
|
@@ -92,16 +93,10 @@ function initializeAccessiModule(app, options) {
|
|
|
92
93
|
app.use(edgeRateLimit);
|
|
93
94
|
}
|
|
94
95
|
if (((_c = options.http) === null || _c === void 0 ? void 0 : _c.securityHeaders) !== false) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
100
|
-
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
101
|
-
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
102
|
-
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
|
|
103
|
-
return next();
|
|
104
|
-
});
|
|
96
|
+
const securityHeaders = (0, securityHeaders_1.createAccessiSecurityHeadersMiddleware)((_d = options.http) === null || _d === void 0 ? void 0 : _d.securityHeaders, isAccessiRoute, { isOpenApiUi: (path) => (0, OpenApiConfig_1.isOpenApiRequestPath)(path, resolvedOpenApi) });
|
|
97
|
+
if (securityHeaders) {
|
|
98
|
+
app.use(securityHeaders);
|
|
99
|
+
}
|
|
105
100
|
}
|
|
106
101
|
app.use((req, res, next) => {
|
|
107
102
|
if (!isAccessiRoute(req.path)) {
|
|
@@ -116,8 +111,8 @@ function initializeAccessiModule(app, options) {
|
|
|
116
111
|
const nestExpressInstance = new platform_express_1.ExpressAdapter(nestHostApp);
|
|
117
112
|
const nestApp = yield core_1.NestFactory.create(AccessiModule_1.AccessiModule.forRoot(options), nestExpressInstance, Object.assign({ bufferLogs: options.bufferLogs !== false }, (options.logger ? { logger: options.logger } : {})));
|
|
118
113
|
logger.info("Applicazione Nest accessi creata.");
|
|
119
|
-
if (((
|
|
120
|
-
nestApp.enableCors((
|
|
114
|
+
if (((_e = options.http) === null || _e === void 0 ? void 0 : _e.cors) !== false) {
|
|
115
|
+
nestApp.enableCors((_g = (_f = options.http) === null || _f === void 0 ? void 0 : _f.cors) !== null && _g !== void 0 ? _g : { exposedHeaders: ['X-Total-Count'] });
|
|
121
116
|
}
|
|
122
117
|
nestApp.useGlobalPipes((0, accessiValidation_1.createAccessiValidationPipe)());
|
|
123
118
|
nestApp.useGlobalFilters(new AccessiHttpExceptionFilter_1.AccessiHttpExceptionFilter());
|
|
@@ -232,6 +227,12 @@ Object.defineProperty(exports, "buildAccessiJwks", { enumerable: true, get: func
|
|
|
232
227
|
Object.defineProperty(exports, "createAccessiJwksHandler", { enumerable: true, get: function () { return jwks_2.createAccessiJwksHandler; } });
|
|
233
228
|
Object.defineProperty(exports, "getAccessiJwksPath", { enumerable: true, get: function () { return jwks_2.getAccessiJwksPath; } });
|
|
234
229
|
Object.defineProperty(exports, "setupAccessiJwks", { enumerable: true, get: function () { return jwks_2.setupAccessiJwks; } });
|
|
230
|
+
var securityHeaders_2 = require("./security/securityHeaders");
|
|
231
|
+
Object.defineProperty(exports, "applyAccessiBaseSecurityHeaders", { enumerable: true, get: function () { return securityHeaders_2.applyAccessiBaseSecurityHeaders; } });
|
|
232
|
+
Object.defineProperty(exports, "applyAccessiContentSecurityPolicy", { enumerable: true, get: function () { return securityHeaders_2.applyAccessiContentSecurityPolicy; } });
|
|
233
|
+
Object.defineProperty(exports, "buildAccessiContentSecurityPolicy", { enumerable: true, get: function () { return securityHeaders_2.buildAccessiContentSecurityPolicy; } });
|
|
234
|
+
Object.defineProperty(exports, "createAccessiSecurityHeadersMiddleware", { enumerable: true, get: function () { return securityHeaders_2.createAccessiSecurityHeadersMiddleware; } });
|
|
235
|
+
Object.defineProperty(exports, "resolveAccessiSecurityHeaders", { enumerable: true, get: function () { return securityHeaders_2.resolveAccessiSecurityHeaders; } });
|
|
235
236
|
var jwtTokenOptions_1 = require("./security/jwtTokenOptions");
|
|
236
237
|
Object.defineProperty(exports, "getAccessiAccessTokenSigningConfig", { enumerable: true, get: function () { return jwtTokenOptions_1.getAccessiAccessTokenSigningConfig; } });
|
|
237
238
|
Object.defineProperty(exports, "getAccessiAccessTokenVerificationConfig", { enumerable: true, get: function () { return jwtTokenOptions_1.getAccessiAccessTokenVerificationConfig; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n if (options.http?.securityHeaders !== false) {\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'SAMEORIGIN');\n res.setHeader('Referrer-Policy', 'no-referrer');\n res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');\n return next();\n });\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport { auditAccessi } from './security/audit';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/accessi-module/index.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { Application, Request } from \"express\";\nimport { NestFactory } from \"@nestjs/core\";\nimport { ExpressAdapter } from \"@nestjs/platform-express\";\nimport type { INestApplication } from \"@nestjs/common\";\nimport type { OpenAPIObject } from \"@nestjs/swagger\";\nimport { AccessiModule, AccessiOptions } from \"./AccessiModule\";\nimport { Logger } from \"../Logger\";\nimport { AuthService } from \"./Services/AuthService/AuthService\";\nimport {\n buildOpenApiExcludePaths,\n isOpenApiRequestPath,\n resolveAccessiOpenApiOptions,\n setupOpenApi\n} from \"../openapi/OpenApiConfig\";\nimport {\n beginAccessiAuthInitialization,\n failAccessiAuthInitialization,\n setAccessiAuthService\n} from \"./middleware/authenticateGen\";\nimport { registerAccessiModuleServices } from \"./accessiRuntime\";\nimport { logAccessiStartup } from \"./startupLog\";\nimport { createAccessiValidationPipe } from './security/accessiValidation';\nimport { AccessiHttpExceptionFilter } from './security/AccessiHttpExceptionFilter';\nimport { assertEmailConfigured } from './security/emailConfiguration';\nimport { getAccessiJwksPath, setupAccessiJwks } from './security/jwks';\nimport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nimport { createAccessiSecurityHeadersMiddleware } from './security/securityHeaders';\n\n/** Esito del bootstrap Express di Accessi. */\nexport interface AccessiModuleInitializationResult {\n /** Sotto-app Nest che serve `/api/accessi/*` e la documentazione. */\n nestApp: INestApplication;\n /** Documento OpenAPI generato, mergiabile nel documento unico dell'host. */\n document: OpenAPIObject;\n}\n\nfunction describeDatabaseTarget(options: AccessiOptions): string {\n const dbOptions = options.databaseOptions as {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n };\n\n return `${dbOptions.host ?? \"?\"}:${dbOptions.port ?? \"?\"} -> ${dbOptions.database ?? \"?\"} as ${dbOptions.user ?? \"?\"}`;\n}\n\n/**\n * Monta il modulo Accessi in un'applicazione Express gia esistente.\n *\n * Il bootstrap crea un host Nest isolato per le rotte `/api/accessi`, inizializza la\n * documentazione OpenAPI, validazione ed error handler, quindi rende disponibile\n * `authorizeAccessi` al resto dell'app.\n * Attendere questa Promise prima di aprire la porta HTTP: durante il bootstrap il middleware\n * restituisce `ACCESSI_AUTH_INITIALIZING` invece di autorizzare richieste parzialmente inizializzate.\n *\n * @param app Applicazione Express ospitante. Non viene sostituita ne vengono intercettate rotte estranee ad Accessi.\n * @param options Configurazione riservata del modulo; proviene normalmente da variabili d'ambiente o secret manager.\n * @returns Il sotto-app Nest e il documento OpenAPI generato (utile per il merge nell'host).\n */\nexport async function initializeAccessiModule(\n app: Application,\n options: AccessiOptions\n): Promise<AccessiModuleInitializationResult> {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n const logger: Logger = new Logger(\"initializeAccessiModule\");\n beginAccessiAuthInitialization();\n const startedAt = performance.now();\n const resolvedOpenApi = resolveAccessiOpenApiOptions(options.openapi);\n\n try {\n logger.info(\"Inizializzazione modulo accessi avviata.\");\n logger.info(`Target database accessi: ${describeDatabaseTarget(options)}`);\n logger.info(\n `Configurazione accessi: autoUpdateDatabase=${options.autoUpdateDatabase !== false}, legacyPasswordMigrationOnStartup=${options.legacyPasswordMigrationOnStartup !== false}`\n );\n const nestHostApp = express();\n if (options.http?.trustProxy !== undefined) {\n app.set('trust proxy', options.http.trustProxy);\n nestHostApp.set('trust proxy', options.http.trustProxy);\n }\n const jwksPath = getAccessiJwksPath(options);\n const isAccessiRoute = (path: string) =>\n path === \"/api/accessi\" ||\n path.startsWith(\"/api/accessi/\") ||\n isOpenApiRequestPath(path, resolvedOpenApi) ||\n (jwksPath !== undefined && path === jwksPath);\n const edgeRateLimit = options.edgeRateLimit\n ? createAccessiEdgeRateLimitMiddleware({\n ...options.edgeRateLimit,\n match: options.edgeRateLimit.match ?? ((path) => isAccessiRoute(path)),\n })\n : undefined;\n if (edgeRateLimit) {\n app.use(edgeRateLimit);\n }\n if (options.http?.securityHeaders !== false) {\n const securityHeaders = createAccessiSecurityHeadersMiddleware(\n options.http?.securityHeaders,\n isAccessiRoute,\n { isOpenApiUi: (path) => isOpenApiRequestPath(path, resolvedOpenApi) },\n );\n if (securityHeaders) {\n app.use(securityHeaders);\n }\n }\n\n app.use((req: Request, res, next) => {\n if (!isAccessiRoute(req.path)) {\n return next();\n }\n\n return nestHostApp(req, res, next);\n });\n\n setupAccessiJwks(app, options);\n if (jwksPath) {\n logger.info(`JWKS accessi disponibile su: ${jwksPath}`);\n }\n\n const nestExpressInstance = new ExpressAdapter(nestHostApp);\n\n const nestApp = await NestFactory.create(AccessiModule.forRoot(options), nestExpressInstance, {\n bufferLogs: options.bufferLogs !== false,\n ...(options.logger ? { logger: options.logger } : {})\n });\n logger.info(\"Applicazione Nest accessi creata.\");\n\n if (options.http?.cors !== false) {\n nestApp.enableCors(options.http?.cors ?? { exposedHeaders: ['X-Total-Count'] });\n }\n nestApp.useGlobalPipes(createAccessiValidationPipe());\n nestApp.useGlobalFilters(new AccessiHttpExceptionFilter());\n\n nestApp.setGlobalPrefix('api', {\n exclude: buildOpenApiExcludePaths(resolvedOpenApi)\n });\n\n const document = setupOpenApi(nestApp, resolvedOpenApi);\n logger.info(\"Avvio init del modulo accessi.\");\n await nestApp.init();\n logger.info(\"Init del modulo accessi completata.\");\n if (options.legacyPasswordMigrationOnStartup !== false) {\n logger.info(\"Avvio migrazione password legacy accessi.\");\n const passwordMigrationService = nestApp.get(AuthService);\n await passwordMigrationService.migrateLegacyEncryptedPasswords();\n logger.info(\"Migrazione password legacy accessi completata.\");\n }\n\n const accessiServices = registerAccessiModuleServices(app, nestApp);\n app.locals.accessiAuthService = accessiServices.authenticateGenService;\n setAccessiAuthService(accessiServices.authenticateGenService);\n logAccessiStartup(options, resolvedOpenApi);\n const elapsedMs = performance.now() - startedAt;\n logger.info(`Accessi initialized. Tempo totale bootstrap: ${elapsedMs.toFixed(2)} ms`);\n\n return { nestApp, document };\n } catch (error) {\n failAccessiAuthInitialization(error);\n logger.error(\n \"Errore in initialize AccessiModule:\",\n error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : { error: String(error) }\n );\n throw error;\n }\n}\n\nexport { AccessiModule } from \"./AccessiModule\";\nexport { AccessiIntrospectionController } from \"./Controllers/AccessiIntrospectionController\";\nexport { FederatedAuthExchangeController } from \"./federated-auth/FederatedAuthExchangeController\";\nexport type { AccessiTokenIntrospectionResult } from \"./Services/AuthService/AuthService\";\nexport { AccessiDatabaseUpdater } from \"./database-updates/AccessiDatabaseUpdater\";\nexport type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from \"./AccessiModule\";\nexport type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from \"./AccessiModule\";\nexport type { CatalogScriptsOptions, CatalogScriptChecksumPolicy, ConsoleEntryOptions } from \"./AccessiModule\";\nexport {\n createMemoryConsoleEntryStore,\n createRedisConsoleEntryStore,\n getDefaultConsoleEntryStore\n} from './security/consoleEntry';\nexport type {\n ConsoleEntryRedisClient,\n ConsoleEntryRecord,\n ConsoleEntryStore,\n ConsoleEntryTicket,\n MemoryConsoleEntryStore,\n RedisConsoleEntryStoreOptions\n} from './security/consoleEntry';\nexport {\n createMemoryRateLimitStore,\n createRedisRateLimitStore,\n getDefaultRateLimitStore\n} from './security/rateLimitStore';\nexport type {\n MemoryRateLimitStore,\n RateLimitDecision,\n RateLimitRedisClient,\n RateLimitStore,\n RedisRateLimitStoreOptions\n} from './security/rateLimitStore';\nexport { createAccessiEdgeRateLimitMiddleware } from './security/edgeRateLimit';\nexport type {\n AccessiEdgeRateLimitMiddleware,\n AccessiEdgeRateLimitOptions\n} from './security/edgeRateLimit';\nexport {\n assertValidAccessiOptions,\n validateAccessiOptions\n} from './security/validateOptions';\nexport { auditAccessi } from './security/audit';\nexport {\n createMemorySessionRevocationStore,\n createRedisSessionRevocationStore,\n revokeAccessiUserSessions,\n revokeAccessiUserSessionsIfConfigured,\n isAccessiTokenRevoked,\n getSessionRevocationStore\n} from './security/sessionRevocation';\nexport type {\n MemorySessionRevocationStore,\n RedisSessionRevocationStoreOptions,\n SessionRevocationOptions,\n SessionRevocationRedisClient,\n SessionRevocationStore\n} from './security/sessionRevocation';\nexport {\n createMemoryRefreshTokenRotationStore,\n createRedisRefreshTokenRotationStore,\n consumeRefreshToken,\n getRefreshTokenRotationStore,\n isRefreshTokenFamilyRevoked,\n revokeRefreshTokenFamily\n} from './security/refreshTokenRotation';\nexport type {\n MemoryRefreshTokenRotationStore,\n RedisRefreshTokenRotationStoreOptions,\n RefreshTokenConsumeResult,\n RefreshTokenRotationOptions,\n RefreshTokenRotationRedisClient,\n RefreshTokenRotationStore\n} from './security/refreshTokenRotation';\nexport {\n createMemoryAccessTokenRevocationStore,\n createRedisAccessTokenRevocationStore,\n getAccessTokenRevocationStore,\n isAccessiAccessTokenRevoked,\n revokeAccessiAccessToken,\n revokeAccessiAccessTokenIfConfigured\n} from './security/accessTokenRevocation';\nexport type {\n AccessTokenRevocationOptions,\n AccessTokenRevocationRedisClient,\n AccessTokenRevocationStore,\n MemoryAccessTokenRevocationStore,\n RedisAccessTokenRevocationStoreOptions\n} from './security/accessTokenRevocation';\nexport type {\n AccessiOptionsValidationIssue,\n AccessiOptionsValidationResult\n} from './security/validateOptions';\nexport {\n AccessiCatalogMigrator,\n applyCatalogScripts,\n listPendingCatalogScripts,\n splitSqlStatements,\n analyzeCatalogScript,\n leadingStatementKeyword,\n computeCatalogScriptChecksum,\n discoverCatalogScripts\n} from \"./database-updates/AccessiCatalogMigrator\";\nexport type { CatalogMigrationReport, CatalogScriptMigration } from \"./database-updates/AccessiCatalogMigrator\";\nexport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nexport type {\n ServiceTokenMetadata,\n IssuedServiceToken,\n VerifiedServiceToken,\n IssueServiceTokenInput\n} from './Services/ServiceTokenService/ServiceTokenService';\nexport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nexport type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';\nexport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport type { BootstrapAdminResult } from './Services/AdminBootstrapService/AdminBootstrapService';\nexport {\n getOrCreateAdminBootstrapToken,\n getAdminBootstrapToken,\n clearAdminBootstrapToken,\n isValidAdminBootstrapToken\n} from './security/adminBootstrap';\nexport { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';\nexport { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';\nexport { buildLoginAsUrl, LOGIN_AS_QUERY_PARAM } from './security/loginAs';\nexport {\n buildAccessiJwks,\n createAccessiJwksHandler,\n getAccessiJwksPath,\n setupAccessiJwks\n} from './security/jwks';\nexport type { AccessiJwksDocument, AccessiJwksKey } from './security/jwks';\nexport {\n applyAccessiBaseSecurityHeaders,\n applyAccessiContentSecurityPolicy,\n buildAccessiContentSecurityPolicy,\n createAccessiSecurityHeadersMiddleware,\n resolveAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport type {\n AccessiCspDirectives,\n AccessiCspOptions,\n AccessiCspSurface,\n AccessiSecurityHeadersOptions,\n AccessiSecurityHeadersSetting,\n ResolvedAccessiCsp,\n ResolvedAccessiSecurityHeaders\n} from './security/securityHeaders';\nexport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n resolveAccessiVerificationKeys,\n verifyAccessiJwt\n} from './security/jwtTokenOptions';\nexport type {\n AccessiJwtVerificationConfig,\n AccessiUnknownKeyIdEvent\n} from './security/jwtTokenOptions';\nexport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nexport type { FederatedAuthenticationResult, FederatedIdentity, FederatedProvider, VerifiedFederatedIdentity } from './federated-auth/FederatedAuthTypes';\nexport * from \"./Dtos\";\nexport {\n authorizeAccessi,\n authenticateGen\n} from \"./middleware/authenticateGen\";\nexport { accessiRequirement } from \"./middleware/accessiRequirements\";\nexport {\n registerAccessiModuleServices,\n getAccessiModuleServices,\n ACCESSI_MODULE_SERVICES_LOCALS_KEY\n} from \"./accessiRuntime\";\nexport type { AccessiModuleServices } from \"./accessiRuntime\";\nexport type {\n AccessiAuthorizationOptions,\n AccessiRequirementNode,\n AccessiCustomRequirementContext,\n AccessiCustomRequirementHandler\n} from \"./middleware/accessiRequirements\";\n\nexport {\n checkAccessiReadiness,\n checkAccessiDatabase,\n collectAccessiHealthStores,\n createAccessiLiveReport,\n readinessHttpStatus\n} from './health/readiness';\nexport type {\n AccessiHealthCheckResult,\n AccessiHealthStore,\n AccessiLiveReport,\n AccessiReadinessCheck,\n AccessiReadinessDependencies,\n AccessiReadinessReport\n} from './health/readiness';\nexport { createAccessiHealthModule } from './health/nest';\nexport type { AccessiHealthModuleOptions } from './health/nest';\n\n"]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from 'express';
|
|
2
|
+
/** Direttive CSP personalizzabili; `false` rimuove la direttiva. */
|
|
3
|
+
export type AccessiCspDirectives = Record<string, string[] | false>;
|
|
4
|
+
/** Opzioni della Content Security Policy di Accessi. */
|
|
5
|
+
export interface AccessiCspOptions {
|
|
6
|
+
/** `false` disabilita solo la CSP, lasciando gli altri header. Default: abilitata. */
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
/** Invia `Content-Security-Policy-Report-Only` invece dell'header bloccante. */
|
|
9
|
+
reportOnly?: boolean;
|
|
10
|
+
/** Endpoint `report-uri` per la raccolta delle violazioni. */
|
|
11
|
+
reportUri?: string;
|
|
12
|
+
/** Origini aggiuntive per `connect-src`, es. API su un dominio diverso. */
|
|
13
|
+
connectSrc?: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Override delle direttive (vincono sui default). Per esempio
|
|
16
|
+
* `{ "img-src": ["'self'", "data:", "https:"] }`.
|
|
17
|
+
*/
|
|
18
|
+
directives?: AccessiCspDirectives;
|
|
19
|
+
/**
|
|
20
|
+
* La UI Swagger usa script e stili inline generati a runtime.
|
|
21
|
+
* Default `true`: la CSP di OpenAPI include `'unsafe-inline'` solo lì.
|
|
22
|
+
*/
|
|
23
|
+
swaggerUnsafeInline?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Header di sicurezza applicati alle rotte Accessi. */
|
|
26
|
+
export interface AccessiSecurityHeadersOptions {
|
|
27
|
+
/** `false` disabilita tutti gli header gestiti da Accessi. */
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
/** `X-Frame-Options`; `false` non lo invia. Default: `SAMEORIGIN`. */
|
|
30
|
+
frameOptions?: string | false;
|
|
31
|
+
/** `Referrer-Policy`; `false` non la invia. Default: `no-referrer`. */
|
|
32
|
+
referrerPolicy?: string | false;
|
|
33
|
+
/** `Permissions-Policy`; `false` non la invia. */
|
|
34
|
+
permissionsPolicy?: string | false;
|
|
35
|
+
/** `Cache-Control` della shell console. Default: `no-store, max-age=0`. */
|
|
36
|
+
cacheControl?: string | false;
|
|
37
|
+
/** CSP; `false` la disabilita. Default: abilitata. */
|
|
38
|
+
contentSecurityPolicy?: false | AccessiCspOptions;
|
|
39
|
+
}
|
|
40
|
+
export type AccessiSecurityHeadersSetting = boolean | AccessiSecurityHeadersOptions;
|
|
41
|
+
export interface ResolvedAccessiCsp {
|
|
42
|
+
reportOnly: boolean;
|
|
43
|
+
reportUri?: string;
|
|
44
|
+
connectSrc: string[];
|
|
45
|
+
directives: AccessiCspDirectives;
|
|
46
|
+
swaggerUnsafeInline: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ResolvedAccessiSecurityHeaders {
|
|
49
|
+
frameOptions: string;
|
|
50
|
+
referrerPolicy: string;
|
|
51
|
+
permissionsPolicy: string;
|
|
52
|
+
cacheControl: string;
|
|
53
|
+
contentSecurityPolicy: false | ResolvedAccessiCsp;
|
|
54
|
+
}
|
|
55
|
+
/** Superficie della risposta: cambia solo la CSP, non gli altri header. */
|
|
56
|
+
export type AccessiCspSurface = 'console' | 'openapi' | 'api';
|
|
57
|
+
/**
|
|
58
|
+
* Risolve la configurazione degli header. `undefined` e `true` equivalgono ai
|
|
59
|
+
* default; `false` disabilita tutto. La forma booleana storica resta valida.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveAccessiSecurityHeaders(setting: AccessiSecurityHeadersSetting | undefined): ResolvedAccessiSecurityHeaders | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Costruisce la CSP per la superficie richiesta.
|
|
64
|
+
*
|
|
65
|
+
* La console usa un nonce per i due script inline della shell; la UI Swagger
|
|
66
|
+
* richiede `'unsafe-inline'` (documentato in `docs/security-headers.md`) e non
|
|
67
|
+
* riceve mai il nonce della console.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildAccessiContentSecurityPolicy(resolved: ResolvedAccessiSecurityHeaders, surface: AccessiCspSurface, options?: {
|
|
70
|
+
nonce?: string;
|
|
71
|
+
connectSrc?: string[];
|
|
72
|
+
}): string | undefined;
|
|
73
|
+
/** Applica l'header CSP corretto per la superficie, se configurata. */
|
|
74
|
+
export declare function applyAccessiContentSecurityPolicy(res: Pick<Response, 'setHeader'>, resolved: ResolvedAccessiSecurityHeaders, surface: AccessiCspSurface, options?: {
|
|
75
|
+
nonce?: string;
|
|
76
|
+
connectSrc?: string[];
|
|
77
|
+
}): string | undefined;
|
|
78
|
+
/** Header comuni (frame, referrer, permessi) senza la CSP. */
|
|
79
|
+
export declare function applyAccessiBaseSecurityHeaders(res: Pick<Response, 'setHeader'>, resolved: ResolvedAccessiSecurityHeaders): void;
|
|
80
|
+
/**
|
|
81
|
+
* Middleware per host Express/Nest.
|
|
82
|
+
*
|
|
83
|
+
* Applica gli header solo alle rotte Accessi. La CSP della console viene
|
|
84
|
+
* sovrascritta dal controller con il nonce della richiesta; per la UI OpenAPI
|
|
85
|
+
* vale la variante Swagger.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createAccessiSecurityHeadersMiddleware(setting: AccessiSecurityHeadersSetting | undefined, isAccessiRoute: (path: string) => boolean, options?: {
|
|
88
|
+
isOpenApiUi?: (path: string) => boolean;
|
|
89
|
+
}): ((req: Request, res: Response, next: NextFunction) => void) | undefined;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveAccessiSecurityHeaders = resolveAccessiSecurityHeaders;
|
|
4
|
+
exports.buildAccessiContentSecurityPolicy = buildAccessiContentSecurityPolicy;
|
|
5
|
+
exports.applyAccessiContentSecurityPolicy = applyAccessiContentSecurityPolicy;
|
|
6
|
+
exports.applyAccessiBaseSecurityHeaders = applyAccessiBaseSecurityHeaders;
|
|
7
|
+
exports.createAccessiSecurityHeadersMiddleware = createAccessiSecurityHeadersMiddleware;
|
|
8
|
+
const DEFAULTS = {
|
|
9
|
+
frameOptions: 'SAMEORIGIN',
|
|
10
|
+
referrerPolicy: 'no-referrer',
|
|
11
|
+
permissionsPolicy: 'camera=(), microphone=(), geolocation=()',
|
|
12
|
+
cacheControl: 'no-store, max-age=0',
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Risolve la configurazione degli header. `undefined` e `true` equivalgono ai
|
|
16
|
+
* default; `false` disabilita tutto. La forma booleana storica resta valida.
|
|
17
|
+
*/
|
|
18
|
+
function resolveAccessiSecurityHeaders(setting) {
|
|
19
|
+
var _a, _b, _c, _d, _e, _f;
|
|
20
|
+
if (setting === false)
|
|
21
|
+
return undefined;
|
|
22
|
+
const options = setting === true || setting === undefined ? {} : setting;
|
|
23
|
+
if (options.enabled === false)
|
|
24
|
+
return undefined;
|
|
25
|
+
const csp = options.contentSecurityPolicy;
|
|
26
|
+
return {
|
|
27
|
+
frameOptions: options.frameOptions === false ? '' : ((_a = options.frameOptions) !== null && _a !== void 0 ? _a : DEFAULTS.frameOptions),
|
|
28
|
+
referrerPolicy: options.referrerPolicy === false ? '' : ((_b = options.referrerPolicy) !== null && _b !== void 0 ? _b : DEFAULTS.referrerPolicy),
|
|
29
|
+
permissionsPolicy: options.permissionsPolicy === false
|
|
30
|
+
? ''
|
|
31
|
+
: ((_c = options.permissionsPolicy) !== null && _c !== void 0 ? _c : DEFAULTS.permissionsPolicy),
|
|
32
|
+
cacheControl: options.cacheControl === false ? '' : ((_d = options.cacheControl) !== null && _d !== void 0 ? _d : DEFAULTS.cacheControl),
|
|
33
|
+
contentSecurityPolicy: csp === false || (csp === null || csp === void 0 ? void 0 : csp.enabled) === false
|
|
34
|
+
? false
|
|
35
|
+
: Object.assign(Object.assign({ reportOnly: (csp === null || csp === void 0 ? void 0 : csp.reportOnly) === true }, ((csp === null || csp === void 0 ? void 0 : csp.reportUri) ? { reportUri: csp.reportUri } : {})), { connectSrc: (_e = csp === null || csp === void 0 ? void 0 : csp.connectSrc) !== null && _e !== void 0 ? _e : [], directives: (_f = csp === null || csp === void 0 ? void 0 : csp.directives) !== null && _f !== void 0 ? _f : {}, swaggerUnsafeInline: (csp === null || csp === void 0 ? void 0 : csp.swaggerUnsafeInline) !== false }),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function frameAncestors(frameOptions) {
|
|
39
|
+
switch (frameOptions.toUpperCase()) {
|
|
40
|
+
case 'DENY':
|
|
41
|
+
return "'none'";
|
|
42
|
+
case 'SAMEORIGIN':
|
|
43
|
+
default:
|
|
44
|
+
return "'self'";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const BASE_DIRECTIVES = {
|
|
48
|
+
'default-src': ["'self'"],
|
|
49
|
+
'base-uri': ["'none'"],
|
|
50
|
+
'object-src': ["'none'"],
|
|
51
|
+
'form-action': ["'self'"],
|
|
52
|
+
'img-src': ["'self'", 'data:'],
|
|
53
|
+
'font-src': ["'self'"],
|
|
54
|
+
'style-src': ["'self'"],
|
|
55
|
+
'script-src': ["'self'"],
|
|
56
|
+
'connect-src': ["'self'"],
|
|
57
|
+
};
|
|
58
|
+
function listOf(directives, name) {
|
|
59
|
+
const value = directives[name];
|
|
60
|
+
return Array.isArray(value) ? value : [];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Costruisce la CSP per la superficie richiesta.
|
|
64
|
+
*
|
|
65
|
+
* La console usa un nonce per i due script inline della shell; la UI Swagger
|
|
66
|
+
* richiede `'unsafe-inline'` (documentato in `docs/security-headers.md`) e non
|
|
67
|
+
* riceve mai il nonce della console.
|
|
68
|
+
*/
|
|
69
|
+
function buildAccessiContentSecurityPolicy(resolved, surface, options = {}) {
|
|
70
|
+
var _a;
|
|
71
|
+
const csp = resolved.contentSecurityPolicy;
|
|
72
|
+
if (!csp)
|
|
73
|
+
return undefined;
|
|
74
|
+
const directives = {};
|
|
75
|
+
for (const [name, value] of Object.entries(BASE_DIRECTIVES)) {
|
|
76
|
+
directives[name] = Array.isArray(value) ? [...value] : value;
|
|
77
|
+
}
|
|
78
|
+
if (resolved.frameOptions) {
|
|
79
|
+
directives['frame-ancestors'] = [frameAncestors(resolved.frameOptions)];
|
|
80
|
+
}
|
|
81
|
+
const connectSrc = new Set([...listOf(directives, 'connect-src'), ...csp.connectSrc, ...((_a = options.connectSrc) !== null && _a !== void 0 ? _a : [])]);
|
|
82
|
+
directives['connect-src'] = [...connectSrc];
|
|
83
|
+
if (surface === 'console') {
|
|
84
|
+
if (options.nonce) {
|
|
85
|
+
directives['script-src'] = [...listOf(directives, 'script-src'), `'nonce-${options.nonce}'`];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (surface === 'openapi' && csp.swaggerUnsafeInline) {
|
|
89
|
+
directives['script-src'] = [...listOf(directives, 'script-src'), "'unsafe-inline'"];
|
|
90
|
+
directives['style-src'] = [...listOf(directives, 'style-src'), "'unsafe-inline'"];
|
|
91
|
+
}
|
|
92
|
+
for (const [name, value] of Object.entries(csp.directives)) {
|
|
93
|
+
if (value === false)
|
|
94
|
+
delete directives[name];
|
|
95
|
+
else
|
|
96
|
+
directives[name] = [...value];
|
|
97
|
+
}
|
|
98
|
+
if (csp.reportUri)
|
|
99
|
+
directives['report-uri'] = [csp.reportUri];
|
|
100
|
+
return Object.entries(directives)
|
|
101
|
+
.filter(([, value]) => value !== false && value.length > 0)
|
|
102
|
+
.map(([name, value]) => `${name} ${value.join(' ')}`)
|
|
103
|
+
.join('; ');
|
|
104
|
+
}
|
|
105
|
+
/** Applica l'header CSP corretto per la superficie, se configurata. */
|
|
106
|
+
function applyAccessiContentSecurityPolicy(res, resolved, surface, options = {}) {
|
|
107
|
+
const csp = resolved.contentSecurityPolicy;
|
|
108
|
+
if (!csp)
|
|
109
|
+
return undefined;
|
|
110
|
+
const policy = buildAccessiContentSecurityPolicy(resolved, surface, options);
|
|
111
|
+
if (!policy)
|
|
112
|
+
return undefined;
|
|
113
|
+
res.setHeader(csp.reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy', policy);
|
|
114
|
+
return policy;
|
|
115
|
+
}
|
|
116
|
+
/** Header comuni (frame, referrer, permessi) senza la CSP. */
|
|
117
|
+
function applyAccessiBaseSecurityHeaders(res, resolved) {
|
|
118
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
119
|
+
if (resolved.frameOptions)
|
|
120
|
+
res.setHeader('X-Frame-Options', resolved.frameOptions);
|
|
121
|
+
if (resolved.referrerPolicy)
|
|
122
|
+
res.setHeader('Referrer-Policy', resolved.referrerPolicy);
|
|
123
|
+
if (resolved.permissionsPolicy)
|
|
124
|
+
res.setHeader('Permissions-Policy', resolved.permissionsPolicy);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Middleware per host Express/Nest.
|
|
128
|
+
*
|
|
129
|
+
* Applica gli header solo alle rotte Accessi. La CSP della console viene
|
|
130
|
+
* sovrascritta dal controller con il nonce della richiesta; per la UI OpenAPI
|
|
131
|
+
* vale la variante Swagger.
|
|
132
|
+
*/
|
|
133
|
+
function createAccessiSecurityHeadersMiddleware(setting, isAccessiRoute, options = {}) {
|
|
134
|
+
const resolved = resolveAccessiSecurityHeaders(setting);
|
|
135
|
+
if (!resolved)
|
|
136
|
+
return undefined;
|
|
137
|
+
return (req, res, next) => {
|
|
138
|
+
var _a;
|
|
139
|
+
if (!isAccessiRoute(req.path)) {
|
|
140
|
+
next();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
applyAccessiBaseSecurityHeaders(res, resolved);
|
|
144
|
+
if (resolved.contentSecurityPolicy) {
|
|
145
|
+
const surface = ((_a = options.isOpenApiUi) === null || _a === void 0 ? void 0 : _a.call(options, req.path))
|
|
146
|
+
? 'openapi'
|
|
147
|
+
: req.path.startsWith('/api/accessi/console')
|
|
148
|
+
? 'console'
|
|
149
|
+
: 'api';
|
|
150
|
+
applyAccessiContentSecurityPolicy(res, resolved, surface);
|
|
151
|
+
}
|
|
152
|
+
next();
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=securityHeaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityHeaders.js","sourceRoot":"","sources":["../../../src/accessi-module/security/securityHeaders.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NextFunction, Request, Response } from 'express';\n\n/** Direttive CSP personalizzabili; `false` rimuove la direttiva. */\nexport type AccessiCspDirectives = Record<string, string[] | false>;\n\n/** Opzioni della Content Security Policy di Accessi. */\nexport interface AccessiCspOptions {\n /** `false` disabilita solo la CSP, lasciando gli altri header. Default: abilitata. */\n enabled?: boolean;\n /** Invia `Content-Security-Policy-Report-Only` invece dell'header bloccante. */\n reportOnly?: boolean;\n /** Endpoint `report-uri` per la raccolta delle violazioni. */\n reportUri?: string;\n /** Origini aggiuntive per `connect-src`, es. API su un dominio diverso. */\n connectSrc?: string[];\n /**\n * Override delle direttive (vincono sui default). Per esempio\n * `{ \"img-src\": [\"'self'\", \"data:\", \"https:\"] }`.\n */\n directives?: AccessiCspDirectives;\n /**\n * La UI Swagger usa script e stili inline generati a runtime.\n * Default `true`: la CSP di OpenAPI include `'unsafe-inline'` solo lì.\n */\n swaggerUnsafeInline?: boolean;\n}\n\n/** Header di sicurezza applicati alle rotte Accessi. */\nexport interface AccessiSecurityHeadersOptions {\n /** `false` disabilita tutti gli header gestiti da Accessi. */\n enabled?: boolean;\n /** `X-Frame-Options`; `false` non lo invia. Default: `SAMEORIGIN`. */\n frameOptions?: string | false;\n /** `Referrer-Policy`; `false` non la invia. Default: `no-referrer`. */\n referrerPolicy?: string | false;\n /** `Permissions-Policy`; `false` non la invia. */\n permissionsPolicy?: string | false;\n /** `Cache-Control` della shell console. Default: `no-store, max-age=0`. */\n cacheControl?: string | false;\n /** CSP; `false` la disabilita. Default: abilitata. */\n contentSecurityPolicy?: false | AccessiCspOptions;\n}\n\nexport type AccessiSecurityHeadersSetting = boolean | AccessiSecurityHeadersOptions;\n\nexport interface ResolvedAccessiCsp {\n reportOnly: boolean;\n reportUri?: string;\n connectSrc: string[];\n directives: AccessiCspDirectives;\n swaggerUnsafeInline: boolean;\n}\n\nexport interface ResolvedAccessiSecurityHeaders {\n frameOptions: string;\n referrerPolicy: string;\n permissionsPolicy: string;\n cacheControl: string;\n contentSecurityPolicy: false | ResolvedAccessiCsp;\n}\n\n/** Superficie della risposta: cambia solo la CSP, non gli altri header. */\nexport type AccessiCspSurface = 'console' | 'openapi' | 'api';\n\nconst DEFAULTS = {\n frameOptions: 'SAMEORIGIN',\n referrerPolicy: 'no-referrer',\n permissionsPolicy: 'camera=(), microphone=(), geolocation=()',\n cacheControl: 'no-store, max-age=0',\n} as const;\n\n/**\n * Risolve la configurazione degli header. `undefined` e `true` equivalgono ai\n * default; `false` disabilita tutto. La forma booleana storica resta valida.\n */\nexport function resolveAccessiSecurityHeaders(\n setting: AccessiSecurityHeadersSetting | undefined,\n): ResolvedAccessiSecurityHeaders | undefined {\n if (setting === false) return undefined;\n const options: AccessiSecurityHeadersOptions = setting === true || setting === undefined ? {} : setting;\n if (options.enabled === false) return undefined;\n\n const csp = options.contentSecurityPolicy;\n return {\n frameOptions: options.frameOptions === false ? '' : (options.frameOptions ?? DEFAULTS.frameOptions),\n referrerPolicy: options.referrerPolicy === false ? '' : (options.referrerPolicy ?? DEFAULTS.referrerPolicy),\n permissionsPolicy: options.permissionsPolicy === false\n ? ''\n : (options.permissionsPolicy ?? DEFAULTS.permissionsPolicy),\n cacheControl: options.cacheControl === false ? '' : (options.cacheControl ?? DEFAULTS.cacheControl),\n contentSecurityPolicy: csp === false || csp?.enabled === false\n ? false\n : {\n reportOnly: csp?.reportOnly === true,\n ...(csp?.reportUri ? { reportUri: csp.reportUri } : {}),\n connectSrc: csp?.connectSrc ?? [],\n directives: csp?.directives ?? {},\n swaggerUnsafeInline: csp?.swaggerUnsafeInline !== false,\n },\n };\n}\n\nfunction frameAncestors(frameOptions: string): string {\n switch (frameOptions.toUpperCase()) {\n case 'DENY':\n return \"'none'\";\n case 'SAMEORIGIN':\n default:\n return \"'self'\";\n }\n}\n\nconst BASE_DIRECTIVES: AccessiCspDirectives = {\n 'default-src': [\"'self'\"],\n 'base-uri': [\"'none'\"],\n 'object-src': [\"'none'\"],\n 'form-action': [\"'self'\"],\n 'img-src': [\"'self'\", 'data:'],\n 'font-src': [\"'self'\"],\n 'style-src': [\"'self'\"],\n 'script-src': [\"'self'\"],\n 'connect-src': [\"'self'\"],\n};\n\nfunction listOf(directives: AccessiCspDirectives, name: string): string[] {\n const value = directives[name];\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * Costruisce la CSP per la superficie richiesta.\n *\n * La console usa un nonce per i due script inline della shell; la UI Swagger\n * richiede `'unsafe-inline'` (documentato in `docs/security-headers.md`) e non\n * riceve mai il nonce della console.\n */\nexport function buildAccessiContentSecurityPolicy(\n resolved: ResolvedAccessiSecurityHeaders,\n surface: AccessiCspSurface,\n options: { nonce?: string; connectSrc?: string[] } = {},\n): string | undefined {\n const csp = resolved.contentSecurityPolicy;\n if (!csp) return undefined;\n\n const directives: AccessiCspDirectives = {};\n for (const [name, value] of Object.entries(BASE_DIRECTIVES)) {\n directives[name] = Array.isArray(value) ? [...value] : value;\n }\n if (resolved.frameOptions) {\n directives['frame-ancestors'] = [frameAncestors(resolved.frameOptions)];\n }\n\n const connectSrc = new Set([...listOf(directives, 'connect-src'), ...csp.connectSrc, ...(options.connectSrc ?? [])]);\n directives['connect-src'] = [...connectSrc];\n\n if (surface === 'console') {\n if (options.nonce) {\n directives['script-src'] = [...listOf(directives, 'script-src'), `'nonce-${options.nonce}'`];\n }\n } else if (surface === 'openapi' && csp.swaggerUnsafeInline) {\n directives['script-src'] = [...listOf(directives, 'script-src'), \"'unsafe-inline'\"];\n directives['style-src'] = [...listOf(directives, 'style-src'), \"'unsafe-inline'\"];\n }\n\n for (const [name, value] of Object.entries(csp.directives)) {\n if (value === false) delete directives[name];\n else directives[name] = [...value];\n }\n if (csp.reportUri) directives['report-uri'] = [csp.reportUri];\n\n return Object.entries(directives)\n .filter(([, value]) => value !== false && value.length > 0)\n .map(([name, value]) => `${name} ${(value as string[]).join(' ')}`)\n .join('; ');\n}\n\n/** Applica l'header CSP corretto per la superficie, se configurata. */\nexport function applyAccessiContentSecurityPolicy(\n res: Pick<Response, 'setHeader'>,\n resolved: ResolvedAccessiSecurityHeaders,\n surface: AccessiCspSurface,\n options: { nonce?: string; connectSrc?: string[] } = {},\n): string | undefined {\n const csp = resolved.contentSecurityPolicy;\n if (!csp) return undefined;\n const policy = buildAccessiContentSecurityPolicy(resolved, surface, options);\n if (!policy) return undefined;\n res.setHeader(\n csp.reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy',\n policy,\n );\n return policy;\n}\n\n/** Header comuni (frame, referrer, permessi) senza la CSP. */\nexport function applyAccessiBaseSecurityHeaders(\n res: Pick<Response, 'setHeader'>,\n resolved: ResolvedAccessiSecurityHeaders,\n): void {\n res.setHeader('X-Content-Type-Options', 'nosniff');\n if (resolved.frameOptions) res.setHeader('X-Frame-Options', resolved.frameOptions);\n if (resolved.referrerPolicy) res.setHeader('Referrer-Policy', resolved.referrerPolicy);\n if (resolved.permissionsPolicy) res.setHeader('Permissions-Policy', resolved.permissionsPolicy);\n}\n\n/**\n * Middleware per host Express/Nest.\n *\n * Applica gli header solo alle rotte Accessi. La CSP della console viene\n * sovrascritta dal controller con il nonce della richiesta; per la UI OpenAPI\n * vale la variante Swagger.\n */\nexport function createAccessiSecurityHeadersMiddleware(\n setting: AccessiSecurityHeadersSetting | undefined,\n isAccessiRoute: (path: string) => boolean,\n options: { isOpenApiUi?: (path: string) => boolean } = {},\n): ((req: Request, res: Response, next: NextFunction) => void) | undefined {\n const resolved = resolveAccessiSecurityHeaders(setting);\n if (!resolved) return undefined;\n\n return (req: Request, res: Response, next: NextFunction): void => {\n if (!isAccessiRoute(req.path)) {\n next();\n return;\n }\n applyAccessiBaseSecurityHeaders(res, resolved);\n if (resolved.contentSecurityPolicy) {\n const surface: AccessiCspSurface = options.isOpenApiUi?.(req.path)\n ? 'openapi'\n : req.path.startsWith('/api/accessi/console')\n ? 'console'\n : 'api';\n applyAccessiContentSecurityPolicy(res, resolved, surface);\n }\n next();\n };\n}\n"]}
|
|
Binary file
|
|
@@ -26,6 +26,7 @@ const accessiValidation_1 = require("./accessi-module/security/accessiValidation
|
|
|
26
26
|
const AccessiHttpExceptionFilter_1 = require("./accessi-module/security/AccessiHttpExceptionFilter");
|
|
27
27
|
const jwks_1 = require("./accessi-module/security/jwks");
|
|
28
28
|
const edgeRateLimit_1 = require("./accessi-module/security/edgeRateLimit");
|
|
29
|
+
const securityHeaders_1 = require("./accessi-module/security/securityHeaders");
|
|
29
30
|
/**
|
|
30
31
|
* Initializes the unified module that combines Accessi and Allegati functionality
|
|
31
32
|
* @param app Express application instance
|
|
@@ -65,17 +66,11 @@ function initEmilsoftwareModule(app, options) {
|
|
|
65
66
|
if (edgeRateLimit) {
|
|
66
67
|
app.use(edgeRateLimit);
|
|
67
68
|
}
|
|
68
|
-
if ((
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
74
|
-
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
75
|
-
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
76
|
-
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
|
|
77
|
-
return next();
|
|
78
|
-
});
|
|
69
|
+
if ((options === null || options === void 0 ? void 0 : options.accessiOptions) && ((_f = options.accessiOptions.http) === null || _f === void 0 ? void 0 : _f.securityHeaders) !== false) {
|
|
70
|
+
const securityHeaders = (0, securityHeaders_1.createAccessiSecurityHeadersMiddleware)((_g = options.accessiOptions.http) === null || _g === void 0 ? void 0 : _g.securityHeaders, isNestRoute, { isOpenApiUi: (path) => (0, OpenApiConfig_1.isOpenApiRequestPath)(path, resolvedOpenApi) });
|
|
71
|
+
if (securityHeaders) {
|
|
72
|
+
app.use(securityHeaders);
|
|
73
|
+
}
|
|
79
74
|
}
|
|
80
75
|
app.use((req, res, next) => {
|
|
81
76
|
if (!isNestRoute(req.path)) {
|