emilsoftware-utilities 2.0.0-dev.69 → 2.0.0-dev.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessi/resource-server/runtime.js +51 -10
- package/dist/accessi/resource-server/runtime.js.map +1 -1
- package/dist/accessi/resource-server/types.d.ts +9 -2
- package/dist/accessi/resource-server/types.js.map +1 -1
- package/dist/accessi/server/standalone.js +3 -2
- package/dist/accessi/server/standalone.js.map +1 -1
- package/dist/accessi-module/AccessiModule.d.ts +4 -1
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.js +5 -3
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.d.ts +11 -1
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js +12 -4
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/index.d.ts +1 -0
- package/dist/accessi-module/Console/generated/model/index.js +1 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/revokeTokenRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/revokeTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/revokeTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/wiki.js +5 -3
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AuthController.d.ts +2 -1
- package/dist/accessi-module/Controllers/AuthController.js +63 -0
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Dtos/RevokeTokenRequest.d.ts +3 -0
- package/dist/accessi-module/Dtos/RevokeTokenRequest.js +27 -0
- package/dist/accessi-module/Dtos/RevokeTokenRequest.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/AuthService/AuthService.d.ts +22 -2
- package/dist/accessi-module/Services/AuthService/AuthService.js +115 -19
- package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
- package/dist/accessi-module/Services/UserService/UserService.d.ts +6 -0
- package/dist/accessi-module/Services/UserService/UserService.js +61 -5
- package/dist/accessi-module/Services/UserService/UserService.js.map +1 -1
- package/dist/accessi-module/federated-auth/FederatedAuthService.js +5 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.js.map +1 -1
- package/dist/accessi-module/index.d.ts +5 -3
- package/dist/accessi-module/index.js +13 -2
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/security/accessTokenRevocation.d.ts +47 -0
- package/dist/accessi-module/security/accessTokenRevocation.js +143 -0
- package/dist/accessi-module/security/accessTokenRevocation.js.map +1 -0
- package/dist/accessi-module/security/refreshTokenRotation.d.ts +42 -2
- package/dist/accessi-module/security/refreshTokenRotation.js +123 -10
- package/dist/accessi-module/security/refreshTokenRotation.js.map +1 -1
- package/dist/accessi-module/security/sessionRevocation.d.ts +21 -6
- package/dist/accessi-module/security/sessionRevocation.js +51 -5
- package/dist/accessi-module/security/sessionRevocation.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.70.tgz +0 -0
- package/docs/accessi-openapi-fingerprint.json +2 -0
- package/package.json +3 -3
- package/dist/emilsoftware-utilities-2.0.0-dev.69.tgz +0 -0
|
@@ -40,6 +40,54 @@ function createAccessiResourceServer(options) {
|
|
|
40
40
|
function mergeIntrospectionUser(payload, user) {
|
|
41
41
|
return Object.assign(Object.assign(Object.assign({}, (payload !== null && payload !== void 0 ? payload : { typ: "access" })), user), { typ: "access", utente: user });
|
|
42
42
|
}
|
|
43
|
+
/** Issued-at in millisecondi, con fallback su `iat` per i token legacy. */
|
|
44
|
+
function resolveIssuedAtMs(payload) {
|
|
45
|
+
const issuedAtMs = Number(payload === null || payload === void 0 ? void 0 : payload.iatMs);
|
|
46
|
+
if (Number.isFinite(issuedAtMs) && issuedAtMs > 0)
|
|
47
|
+
return issuedAtMs;
|
|
48
|
+
const issuedAt = Number(payload === null || payload === void 0 ? void 0 : payload.iat);
|
|
49
|
+
if (!Number.isFinite(issuedAt))
|
|
50
|
+
return null;
|
|
51
|
+
return issuedAt * 1000;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Applica gli store di revoca configurati: famiglia refresh, singolo `jti` e
|
|
55
|
+
* cutoff per utente. Il resource server non interroga mai il database Accessi.
|
|
56
|
+
*/
|
|
57
|
+
function assertTokenNotRevoked(payload, codiceUtente, options) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
var _a;
|
|
60
|
+
const revocation = options.revocation;
|
|
61
|
+
if (!revocation)
|
|
62
|
+
return;
|
|
63
|
+
const familyId = typeof payload.fid === "string" ? payload.fid : undefined;
|
|
64
|
+
if (familyId && ((_a = revocation.familyStore) === null || _a === void 0 ? void 0 : _a.isFamilyRevoked)) {
|
|
65
|
+
if (yield revocation.familyStore.isFamilyRevoked(familyId)) {
|
|
66
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_REVOKED", "Sessione revocata per riuso sospetto del refresh token.");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const jti = typeof payload.jti === "string" ? payload.jti : undefined;
|
|
70
|
+
if (jti && revocation.accessTokenStore) {
|
|
71
|
+
if (yield revocation.accessTokenStore.isRevoked(jti)) {
|
|
72
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_REVOKED", "Token revocato.");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (revocation.store) {
|
|
76
|
+
const issuedAtMs = resolveIssuedAtMs(payload);
|
|
77
|
+
if (issuedAtMs === null) {
|
|
78
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token privo di iat.");
|
|
79
|
+
}
|
|
80
|
+
const revokedAt = yield revocation.store.getUserRevocation(codiceUtente);
|
|
81
|
+
const preciseIssuedAtMs = Number(payload.iatMs);
|
|
82
|
+
const isRevoked = revokedAt !== null && (Number.isFinite(preciseIssuedAtMs) && preciseIssuedAtMs > 0
|
|
83
|
+
? issuedAtMs <= revokedAt
|
|
84
|
+
: issuedAtMs < Math.floor(revokedAt / 1000) * 1000);
|
|
85
|
+
if (isRevoked) {
|
|
86
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_REVOKED", "Sessione revocata.");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
43
91
|
/**
|
|
44
92
|
* Autentica la request e applica l'eventuale policy di autorizzazione.
|
|
45
93
|
*
|
|
@@ -48,7 +96,7 @@ function mergeIntrospectionUser(payload, user) {
|
|
|
48
96
|
*/
|
|
49
97
|
function authenticateAccessiRequest(request, runtime) {
|
|
50
98
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
var _a, _b
|
|
99
|
+
var _a, _b;
|
|
52
100
|
const token = (0, contracts_1.extractAccessiBearerToken)(request.headers.authorization);
|
|
53
101
|
if (!token) {
|
|
54
102
|
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_MISSING", "Token Bearer mancante o malformato.");
|
|
@@ -83,15 +131,8 @@ function authenticateAccessiRequest(request, runtime) {
|
|
|
83
131
|
if (!codiceUtente) {
|
|
84
132
|
throw (0, errors_1.accessiAuthError)(401, "AUTH_USER_CODE_MISSING", "Token privo di un utente valido.");
|
|
85
133
|
}
|
|
86
|
-
if (mode === "local" &&
|
|
87
|
-
|
|
88
|
-
if (!Number.isFinite(issuedAt)) {
|
|
89
|
-
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token privo di iat.");
|
|
90
|
-
}
|
|
91
|
-
const revokedAt = yield runtime.options.revocation.store.getUserRevocation(codiceUtente);
|
|
92
|
-
if (revokedAt !== null && issuedAt < Math.floor(revokedAt / 1000)) {
|
|
93
|
-
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_REVOKED", "Sessione revocata.");
|
|
94
|
-
}
|
|
134
|
+
if (mode === "local" && runtime.options.revocation) {
|
|
135
|
+
yield assertTokenNotRevoked(payload, codiceUtente, runtime.options);
|
|
95
136
|
}
|
|
96
137
|
const requirementTree = (0, contracts_1.buildRequirementTree)(runtime.options.authorization);
|
|
97
138
|
if (requirementTree) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Request } from \"express\";\nimport {\n buildRequirementTree,\n evaluateRequirement,\n extractAccessiBearerToken,\n} from \"../contracts\";\nimport type {\n AccessiAccessTokenPayload,\n GrantsResult,\n} from \"../contracts\";\nimport { accessiAuthError } from \"./errors\";\nimport { createAccessiIntrospectionClient } from \"./introspection\";\nimport type { AccessiIntrospectionClient } from \"./introspection\";\nimport { createAccessiTokenVerifier } from \"./token\";\nimport type { AccessiTokenVerifier } from \"./token\";\nimport type {\n AccessiRequestContext,\n AccessiResourceServerOptions,\n} from \"./types\";\n\n/** Request Express arricchita dal resource server. */\nexport interface AccessiAuthenticatedRequest extends Request {\n user?: Record<string, unknown>;\n data?: Record<string, unknown>;\n userGrants?: GrantsResult;\n accessi?: AccessiRequestContext;\n}\n\n/** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */\nexport interface AccessiResourceServerRuntime {\n options: AccessiResourceServerOptions;\n verifier?: AccessiTokenVerifier;\n introspectionClient?: AccessiIntrospectionClient;\n}\n\nfunction resolveMode(options: AccessiResourceServerOptions): \"local\" | \"introspection\" {\n if (options.mode) return options.mode;\n if (options.jwt) return \"local\";\n if (options.introspection) return \"introspection\";\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"Configurare jwt o introspection nel resource server Accessi.\",\n );\n}\n\n/** Valida la configurazione e prepara verificatore e client di introspection. */\nexport function createAccessiResourceServer(\n options: AccessiResourceServerOptions,\n): AccessiResourceServerRuntime {\n const mode = resolveMode(options);\n if (mode === \"local\" && !options.jwt) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode local richiede jwt.\");\n }\n if (mode === \"introspection\" && !options.introspection) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode introspection richiede introspection.\");\n }\n\n return {\n options: { ...options, mode },\n ...(options.jwt ? { verifier: createAccessiTokenVerifier(options.jwt) } : {}),\n ...(options.introspection\n ? { introspectionClient: createAccessiIntrospectionClient(options.introspection) }\n : {}),\n };\n}\n\nfunction mergeIntrospectionUser(\n payload: AccessiAccessTokenPayload | undefined,\n user: Record<string, unknown>,\n): AccessiAccessTokenPayload {\n return {\n ...(payload ?? { typ: \"access\" }),\n ...user,\n typ: \"access\",\n utente: user,\n };\n}\n\n/**\n * Autentica la request e applica l'eventuale policy di autorizzazione.\n *\n * Non accede mai al database Accessi: la verifica e locale oppure delegata\n * all'introspection di Accessi Service.\n */\nexport async function authenticateAccessiRequest(\n request: Request,\n runtime: AccessiResourceServerRuntime,\n): Promise<AccessiRequestContext> {\n const token = extractAccessiBearerToken(request.headers.authorization);\n if (!token) {\n throw accessiAuthError(401, \"AUTH_TOKEN_MISSING\", \"Token Bearer mancante o malformato.\");\n }\n\n const mode = runtime.options.mode ?? \"local\";\n let payload: AccessiAccessTokenPayload | undefined;\n let user: Record<string, unknown> = {};\n let codiceUtente: number | undefined;\n let grants: GrantsResult | undefined;\n\n if (mode === \"local\") {\n if (!runtime.verifier) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Verificatore JWT non configurato.\");\n }\n const verification = await runtime.verifier.verify(token);\n payload = verification.payload;\n user = verification.user;\n codiceUtente = verification.codiceUtente;\n } else {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Client introspection non configurato.\");\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n user = introspection.user ?? {};\n codiceUtente = introspection.codiceUtente;\n grants = introspection.grants;\n payload = mergeIntrospectionUser(undefined, user);\n }\n\n if (!codiceUtente) {\n throw accessiAuthError(401, \"AUTH_USER_CODE_MISSING\", \"Token privo di un utente valido.\");\n }\n\n if (mode === \"local\" && runtime.options.revocation?.store) {\n const issuedAt = Number(payload?.iat);\n if (!Number.isFinite(issuedAt)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token privo di iat.\");\n }\n const revokedAt = await runtime.options.revocation.store.getUserRevocation(codiceUtente);\n if (revokedAt !== null && issuedAt < Math.floor(revokedAt / 1000)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_REVOKED\", \"Sessione revocata.\");\n }\n }\n\n const requirementTree = buildRequirementTree(runtime.options.authorization);\n if (requirementTree) {\n if (!grants) {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(\n 500,\n \"AUTH_GRANTS_SOURCE_MISSING\",\n \"La policy richiede grant ma introspection non e configurata.\",\n );\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n grants = introspection.grants;\n if (introspection.user) {\n user = introspection.user;\n payload = mergeIntrospectionUser(payload, user);\n }\n }\n\n const hasPermissions = await evaluateRequirement(\n requirementTree,\n {\n req: request,\n decodedToken: payload,\n userCode: codiceUtente,\n getGrantsResult: async () => grants ?? {},\n },\n runtime.options.authorization,\n );\n if (!hasPermissions) {\n throw accessiAuthError(\n 403,\n \"AUTH_INSUFFICIENT_PERMISSIONS\",\n \"Permessi insufficienti per questa operazione.\",\n );\n }\n }\n\n const authenticatedRequest = request as AccessiAuthenticatedRequest;\n const authPayload: Record<string, unknown> = payload ?? {\n typ: \"access\",\n codiceUtente,\n utente: user,\n };\n authenticatedRequest.user = authPayload;\n authenticatedRequest.data = authPayload;\n if (grants) authenticatedRequest.userGrants = grants;\n authenticatedRequest.accessi = {\n token,\n user,\n codiceUtente,\n ...(grants ? { grants } : {}),\n payload: authPayload,\n };\n return authenticatedRequest.accessi;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Request } from \"express\";\nimport {\n buildRequirementTree,\n evaluateRequirement,\n extractAccessiBearerToken,\n} from \"../contracts\";\nimport type {\n AccessiAccessTokenPayload,\n GrantsResult,\n} from \"../contracts\";\nimport { accessiAuthError } from \"./errors\";\nimport { createAccessiIntrospectionClient } from \"./introspection\";\nimport type { AccessiIntrospectionClient } from \"./introspection\";\nimport { createAccessiTokenVerifier } from \"./token\";\nimport type { AccessiTokenVerifier } from \"./token\";\nimport type {\n AccessiRequestContext,\n AccessiResourceServerOptions,\n} from \"./types\";\n\n/** Request Express arricchita dal resource server. */\nexport interface AccessiAuthenticatedRequest extends Request {\n user?: Record<string, unknown>;\n data?: Record<string, unknown>;\n userGrants?: GrantsResult;\n accessi?: AccessiRequestContext;\n}\n\n/** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */\nexport interface AccessiResourceServerRuntime {\n options: AccessiResourceServerOptions;\n verifier?: AccessiTokenVerifier;\n introspectionClient?: AccessiIntrospectionClient;\n}\n\nfunction resolveMode(options: AccessiResourceServerOptions): \"local\" | \"introspection\" {\n if (options.mode) return options.mode;\n if (options.jwt) return \"local\";\n if (options.introspection) return \"introspection\";\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"Configurare jwt o introspection nel resource server Accessi.\",\n );\n}\n\n/** Valida la configurazione e prepara verificatore e client di introspection. */\nexport function createAccessiResourceServer(\n options: AccessiResourceServerOptions,\n): AccessiResourceServerRuntime {\n const mode = resolveMode(options);\n if (mode === \"local\" && !options.jwt) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode local richiede jwt.\");\n }\n if (mode === \"introspection\" && !options.introspection) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode introspection richiede introspection.\");\n }\n\n return {\n options: { ...options, mode },\n ...(options.jwt ? { verifier: createAccessiTokenVerifier(options.jwt) } : {}),\n ...(options.introspection\n ? { introspectionClient: createAccessiIntrospectionClient(options.introspection) }\n : {}),\n };\n}\n\nfunction mergeIntrospectionUser(\n payload: AccessiAccessTokenPayload | undefined,\n user: Record<string, unknown>,\n): AccessiAccessTokenPayload {\n return {\n ...(payload ?? { typ: \"access\" }),\n ...user,\n typ: \"access\",\n utente: user,\n };\n}\n\n/** Issued-at in millisecondi, con fallback su `iat` per i token legacy. */\nfunction resolveIssuedAtMs(payload: Record<string, unknown> | undefined): number | null {\n const issuedAtMs = Number(payload?.iatMs);\n if (Number.isFinite(issuedAtMs) && issuedAtMs > 0) return issuedAtMs;\n const issuedAt = Number(payload?.iat);\n if (!Number.isFinite(issuedAt)) return null;\n return issuedAt * 1000;\n}\n\n/**\n * Applica gli store di revoca configurati: famiglia refresh, singolo `jti` e\n * cutoff per utente. Il resource server non interroga mai il database Accessi.\n */\nasync function assertTokenNotRevoked(\n payload: AccessiAccessTokenPayload,\n codiceUtente: number,\n options: AccessiResourceServerOptions,\n): Promise<void> {\n const revocation = options.revocation;\n if (!revocation) return;\n\n const familyId = typeof payload.fid === \"string\" ? payload.fid : undefined;\n if (familyId && revocation.familyStore?.isFamilyRevoked) {\n if (await revocation.familyStore.isFamilyRevoked(familyId)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_REVOKED\", \"Sessione revocata per riuso sospetto del refresh token.\");\n }\n }\n\n const jti = typeof payload.jti === \"string\" ? payload.jti : undefined;\n if (jti && revocation.accessTokenStore) {\n if (await revocation.accessTokenStore.isRevoked(jti)) {\n throw accessiAuthError(401, \"AUTH_TOKEN_REVOKED\", \"Token revocato.\");\n }\n }\n\n if (revocation.store) {\n const issuedAtMs = resolveIssuedAtMs(payload as Record<string, unknown>);\n if (issuedAtMs === null) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token privo di iat.\");\n }\n const revokedAt = await revocation.store.getUserRevocation(codiceUtente);\n const preciseIssuedAtMs = Number(payload.iatMs);\n const isRevoked = revokedAt !== null && (\n Number.isFinite(preciseIssuedAtMs) && preciseIssuedAtMs > 0\n ? issuedAtMs <= revokedAt\n : issuedAtMs < Math.floor(revokedAt / 1000) * 1000\n );\n if (isRevoked) {\n throw accessiAuthError(401, \"AUTH_TOKEN_REVOKED\", \"Sessione revocata.\");\n }\n }\n}\n\n/**\n * Autentica la request e applica l'eventuale policy di autorizzazione.\n *\n * Non accede mai al database Accessi: la verifica e locale oppure delegata\n * all'introspection di Accessi Service.\n */\nexport async function authenticateAccessiRequest(\n request: Request,\n runtime: AccessiResourceServerRuntime,\n): Promise<AccessiRequestContext> {\n const token = extractAccessiBearerToken(request.headers.authorization);\n if (!token) {\n throw accessiAuthError(401, \"AUTH_TOKEN_MISSING\", \"Token Bearer mancante o malformato.\");\n }\n\n const mode = runtime.options.mode ?? \"local\";\n let payload: AccessiAccessTokenPayload | undefined;\n let user: Record<string, unknown> = {};\n let codiceUtente: number | undefined;\n let grants: GrantsResult | undefined;\n\n if (mode === \"local\") {\n if (!runtime.verifier) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Verificatore JWT non configurato.\");\n }\n const verification = await runtime.verifier.verify(token);\n payload = verification.payload;\n user = verification.user;\n codiceUtente = verification.codiceUtente;\n } else {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Client introspection non configurato.\");\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n user = introspection.user ?? {};\n codiceUtente = introspection.codiceUtente;\n grants = introspection.grants;\n payload = mergeIntrospectionUser(undefined, user);\n }\n\n if (!codiceUtente) {\n throw accessiAuthError(401, \"AUTH_USER_CODE_MISSING\", \"Token privo di un utente valido.\");\n }\n\n if (mode === \"local\" && runtime.options.revocation) {\n await assertTokenNotRevoked(payload as AccessiAccessTokenPayload, codiceUtente, runtime.options);\n }\n\n const requirementTree = buildRequirementTree(runtime.options.authorization);\n if (requirementTree) {\n if (!grants) {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(\n 500,\n \"AUTH_GRANTS_SOURCE_MISSING\",\n \"La policy richiede grant ma introspection non e configurata.\",\n );\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n grants = introspection.grants;\n if (introspection.user) {\n user = introspection.user;\n payload = mergeIntrospectionUser(payload, user);\n }\n }\n\n const hasPermissions = await evaluateRequirement(\n requirementTree,\n {\n req: request,\n decodedToken: payload,\n userCode: codiceUtente,\n getGrantsResult: async () => grants ?? {},\n },\n runtime.options.authorization,\n );\n if (!hasPermissions) {\n throw accessiAuthError(\n 403,\n \"AUTH_INSUFFICIENT_PERMISSIONS\",\n \"Permessi insufficienti per questa operazione.\",\n );\n }\n }\n\n const authenticatedRequest = request as AccessiAuthenticatedRequest;\n const authPayload: Record<string, unknown> = payload ?? {\n typ: \"access\",\n codiceUtente,\n utente: user,\n };\n authenticatedRequest.user = authPayload;\n authenticatedRequest.data = authPayload;\n if (grants) authenticatedRequest.userGrants = grants;\n authenticatedRequest.accessi = {\n token,\n user,\n codiceUtente,\n ...(grants ? { grants } : {}),\n payload: authPayload,\n };\n return authenticatedRequest.accessi;\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AccessiAuthorizationOptions, AccessiGrant, GrantsResult } from "../contracts";
|
|
2
2
|
import type { SessionRevocationStore } from "../../accessi-module/security/sessionRevocation";
|
|
3
|
+
import type { AccessTokenRevocationStore } from "../../accessi-module/security/accessTokenRevocation";
|
|
4
|
+
import type { RefreshTokenRotationStore } from "../../accessi-module/security/refreshTokenRotation";
|
|
3
5
|
/** Algoritmi JWT supportati dal resource server. */
|
|
4
6
|
export type AccessiJwtAlgorithm = "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512" | "ES256" | "ES384" | "ES512";
|
|
5
7
|
/** Opzioni di verifica locale del JWT. Almeno una tra `secret`, `publicKey` e `jwks` e obbligatoria. */
|
|
@@ -66,9 +68,14 @@ export interface AccessiResourceServerOptions {
|
|
|
66
68
|
introspection?: AccessiIntrospectionOptions;
|
|
67
69
|
/** Policy di autorizzazione opzionale applicata dopo l'autenticazione. */
|
|
68
70
|
authorization?: AccessiAuthorizationOptions;
|
|
69
|
-
/** Store condiviso di revoca
|
|
71
|
+
/** Store condiviso di revoca. Opzionale. */
|
|
70
72
|
revocation?: {
|
|
71
|
-
|
|
73
|
+
/** Revoca per utente: invalida tutti i token emessi prima del cutoff. */
|
|
74
|
+
store?: SessionRevocationStore;
|
|
75
|
+
/** Revoca dei singoli access token tramite `jti`. */
|
|
76
|
+
accessTokenStore?: AccessTokenRevocationStore;
|
|
77
|
+
/** Store di rotazione refresh: applica la revoca delle famiglie sospette. */
|
|
78
|
+
familyStore?: RefreshTokenRotationStore;
|
|
72
79
|
};
|
|
73
80
|
/** Audit strutturato degli errori di autenticazione. Default: true. */
|
|
74
81
|
audit?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccessiAuthorizationOptions,\n AccessiGrant,\n GrantsResult,\n} from \"../contracts\";\nimport type { SessionRevocationStore } from \"../../accessi-module/security/sessionRevocation\";\n\n/** Algoritmi JWT supportati dal resource server. */\nexport type AccessiJwtAlgorithm =\n | \"HS256\"\n | \"HS384\"\n | \"HS512\"\n | \"RS256\"\n | \"RS384\"\n | \"RS512\"\n | \"ES256\"\n | \"ES384\"\n | \"ES512\";\n\n/** Opzioni di verifica locale del JWT. Almeno una tra `secret`, `publicKey` e `jwks` e obbligatoria. */\nexport interface AccessiResourceServerJwtOptions {\n /** Chiave HMAC gia derivata (access key). Alternativa a `serverSecret`. */\n secret?: string;\n /**\n * Segreto Accessi grezzo (`ACCESSI_JWT_SECRET`).\n *\n * Il resource server deriva automaticamente la chiave access con la stessa\n * KDF del server: e il modo consigliato quando si condivide il segreto HS256.\n */\n serverSecret?: string;\n /** Chiave pubblica PEM per algoritmi RS ed ES. */\n publicKey?: string | Buffer;\n /** JWKS remoto per verificare token firmati con chiavi asimmetriche. */\n jwks?: {\n url: string;\n cacheTtlMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n };\n /** Default: HS256 con `secret`, altrimenti RS/ES con `publicKey`/`jwks`. */\n algorithms?: AccessiJwtAlgorithm[];\n /** Issuer atteso (`iss`). */\n issuer?: string;\n /** Audience attesa (`aud`). */\n audience?: string | string[];\n /** Tolleranza orologio in secondi. Default: 5. */\n clockToleranceSeconds?: number;\n}\n\n/** Configurazione del client di introspection verso Accessi Service. */\nexport interface AccessiIntrospectionOptions {\n /** URL completo, es. `https://accessi.example.com/api/accessi/auth/introspect`. */\n url: string;\n /** Service token Accessi con scope `accessi:introspect`. */\n serviceToken: string;\n /** TTL della cache locale dei risultati attivi. Default: 30000 ms. */\n cacheTtlMs?: number;\n /** Timeout HTTP. Default: 3000 ms. */\n timeoutMs?: number;\n /** Fetch iniettabile per test o runtime non-Node. */\n fetch?: typeof fetch;\n}\n\n/** Risultato dell'introspection. */\nexport interface AccessiIntrospectionResult {\n active: boolean;\n user?: Record<string, unknown>;\n codiceUtente?: number;\n grants?: GrantsResult;\n}\n\n/** Modalita di autenticazione del resource server. */\nexport type AccessiResourceServerMode = \"local\" | \"introspection\";\n\n/**\n * Configurazione di un backend fratello che non possiede il database Accessi.\n *\n * - `mode: \"local\"` verifica il JWT con chiave locale e, se servono grant, usa\n * l'introspection per leggerli.\n * - `mode: \"introspection\"` delega la verifica del token ad Accessi Service.\n */\nexport interface AccessiResourceServerOptions {\n mode?: AccessiResourceServerMode;\n jwt?: AccessiResourceServerJwtOptions;\n introspection?: AccessiIntrospectionOptions;\n /** Policy di autorizzazione opzionale applicata dopo l'autenticazione. */\n authorization?: AccessiAuthorizationOptions;\n /** Store condiviso di revoca
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccessiAuthorizationOptions,\n AccessiGrant,\n GrantsResult,\n} from \"../contracts\";\nimport type { SessionRevocationStore } from \"../../accessi-module/security/sessionRevocation\";\nimport type { AccessTokenRevocationStore } from \"../../accessi-module/security/accessTokenRevocation\";\nimport type { RefreshTokenRotationStore } from \"../../accessi-module/security/refreshTokenRotation\";\n\n/** Algoritmi JWT supportati dal resource server. */\nexport type AccessiJwtAlgorithm =\n | \"HS256\"\n | \"HS384\"\n | \"HS512\"\n | \"RS256\"\n | \"RS384\"\n | \"RS512\"\n | \"ES256\"\n | \"ES384\"\n | \"ES512\";\n\n/** Opzioni di verifica locale del JWT. Almeno una tra `secret`, `publicKey` e `jwks` e obbligatoria. */\nexport interface AccessiResourceServerJwtOptions {\n /** Chiave HMAC gia derivata (access key). Alternativa a `serverSecret`. */\n secret?: string;\n /**\n * Segreto Accessi grezzo (`ACCESSI_JWT_SECRET`).\n *\n * Il resource server deriva automaticamente la chiave access con la stessa\n * KDF del server: e il modo consigliato quando si condivide il segreto HS256.\n */\n serverSecret?: string;\n /** Chiave pubblica PEM per algoritmi RS ed ES. */\n publicKey?: string | Buffer;\n /** JWKS remoto per verificare token firmati con chiavi asimmetriche. */\n jwks?: {\n url: string;\n cacheTtlMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n };\n /** Default: HS256 con `secret`, altrimenti RS/ES con `publicKey`/`jwks`. */\n algorithms?: AccessiJwtAlgorithm[];\n /** Issuer atteso (`iss`). */\n issuer?: string;\n /** Audience attesa (`aud`). */\n audience?: string | string[];\n /** Tolleranza orologio in secondi. Default: 5. */\n clockToleranceSeconds?: number;\n}\n\n/** Configurazione del client di introspection verso Accessi Service. */\nexport interface AccessiIntrospectionOptions {\n /** URL completo, es. `https://accessi.example.com/api/accessi/auth/introspect`. */\n url: string;\n /** Service token Accessi con scope `accessi:introspect`. */\n serviceToken: string;\n /** TTL della cache locale dei risultati attivi. Default: 30000 ms. */\n cacheTtlMs?: number;\n /** Timeout HTTP. Default: 3000 ms. */\n timeoutMs?: number;\n /** Fetch iniettabile per test o runtime non-Node. */\n fetch?: typeof fetch;\n}\n\n/** Risultato dell'introspection. */\nexport interface AccessiIntrospectionResult {\n active: boolean;\n user?: Record<string, unknown>;\n codiceUtente?: number;\n grants?: GrantsResult;\n}\n\n/** Modalita di autenticazione del resource server. */\nexport type AccessiResourceServerMode = \"local\" | \"introspection\";\n\n/**\n * Configurazione di un backend fratello che non possiede il database Accessi.\n *\n * - `mode: \"local\"` verifica il JWT con chiave locale e, se servono grant, usa\n * l'introspection per leggerli.\n * - `mode: \"introspection\"` delega la verifica del token ad Accessi Service.\n */\nexport interface AccessiResourceServerOptions {\n mode?: AccessiResourceServerMode;\n jwt?: AccessiResourceServerJwtOptions;\n introspection?: AccessiIntrospectionOptions;\n /** Policy di autorizzazione opzionale applicata dopo l'autenticazione. */\n authorization?: AccessiAuthorizationOptions;\n /** Store condiviso di revoca. Opzionale. */\n revocation?: {\n /** Revoca per utente: invalida tutti i token emessi prima del cutoff. */\n store?: SessionRevocationStore;\n /** Revoca dei singoli access token tramite `jti`. */\n accessTokenStore?: AccessTokenRevocationStore;\n /** Store di rotazione refresh: applica la revoca delle famiglie sospette. */\n familyStore?: RefreshTokenRotationStore;\n };\n /** Audit strutturato degli errori di autenticazione. Default: true. */\n audit?: boolean;\n}\n\n/** Dati allegati alla request dopo l'autenticazione. */\nexport interface AccessiRequestContext {\n token: string;\n user: Record<string, unknown>;\n codiceUtente?: number;\n grants?: GrantsResult;\n payload?: Record<string, unknown>;\n}\n\n/** Grant esposto per compatibilita con il middleware storico. */\nexport type AccessiRequestGrants = AccessiGrant[];\n"]}
|
|
@@ -67,7 +67,7 @@ function createMetrics() {
|
|
|
67
67
|
return { middleware, render };
|
|
68
68
|
}
|
|
69
69
|
function collectHealthStores(options) {
|
|
70
|
-
var _a, _b, _c, _d, _e, _f;
|
|
70
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
71
71
|
const stores = [];
|
|
72
72
|
const seen = new Set();
|
|
73
73
|
const add = (name, store) => {
|
|
@@ -81,7 +81,8 @@ function collectHealthStores(options) {
|
|
|
81
81
|
add('consoleEntry', (_c = options.consoleEntry) === null || _c === void 0 ? void 0 : _c.store);
|
|
82
82
|
add('edgeRateLimit', (_d = options.edgeRateLimit) === null || _d === void 0 ? void 0 : _d.store);
|
|
83
83
|
add('sessionRevocation', (_e = options.sessionRevocation) === null || _e === void 0 ? void 0 : _e.store);
|
|
84
|
-
add('
|
|
84
|
+
add('accessTokenRevocation', (_f = options.accessTokenRevocation) === null || _f === void 0 ? void 0 : _f.store);
|
|
85
|
+
add('refreshTokenRotation', (_g = options.refreshTokenRotation) === null || _g === void 0 ? void 0 : _g.store);
|
|
85
86
|
return stores;
|
|
86
87
|
}
|
|
87
88
|
function checkDatabase(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalone.js","sourceRoot":"","sources":["../../../src/accessi/server/standalone.ts"],"names":[],"mappings":"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","sourcesContent":["import express from 'express';\nimport type { Application, Request, Response } from 'express';\nimport type { Server } from 'http';\nimport { Logger } from '../../Logger';\nimport { Orm } from '../../Orm';\nimport { initializeAccessiModule } from '../../accessi-module';\nimport type {\n AccessiModuleInitializationResult,\n} from '../../accessi-module';\nimport type { AccessiOptions } from '../../accessi-module/AccessiModule';\nimport { createAccessiOptionsFromEnv } from '../../accessi-module/database-updates/accessiOptionsFromEnv';\nimport {\n ACCESSI_SCHEMA_VERSION,\n} from '../../accessi-module/database-updates/accessiSchema';\nimport { AccessiDatabaseUpdater } from '../../accessi-module/database-updates/AccessiDatabaseUpdater';\nimport { assertValidAccessiOptions, validateAccessiOptions } from '../../accessi-module/security/validateOptions';\n\nexport interface AccessiReadinessCheck {\n name: string;\n check: () => boolean | Promise<boolean>;\n}\n\nexport interface AccessiServiceOptions {\n /** Applicazione Express gia esistente. Default: nuova app. */\n app?: Application;\n /** Configurazione completa. Default: `createAccessiOptionsFromEnv()`. */\n accessiOptions?: AccessiOptions;\n port?: number;\n host?: string;\n /** Path base degli endpoint health. Default: `/health`. */\n healthPath?: string;\n /** Espone `/health/metrics` in formato Prometheus. Default: true. */\n metrics?: boolean;\n /** Check aggiuntivi per la readiness. */\n readinessChecks?: AccessiReadinessCheck[];\n /** Timeout chiusura server. Default: 10000 ms. */\n shutdownTimeoutMs?: number;\n}\n\nexport interface AccessiService {\n app: Application;\n nestApp: AccessiModuleInitializationResult['nestApp'];\n document: AccessiModuleInitializationResult['document'];\n start(): Promise<Server>;\n stop(): Promise<void>;\n}\n\ninterface HealthCheckResult {\n ok: boolean;\n detail?: string;\n}\n\nfunction normalizePath(value: string): string {\n return `/${value.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\nfunction createMetrics() {\n const startedAt = Date.now();\n let requests = 0;\n let inFlight = 0;\n const statuses = new Map<string, number>();\n\n const middleware = (_req: Request, res: Response, next: () => void): void => {\n requests += 1;\n inFlight += 1;\n res.on('finish', () => {\n inFlight = Math.max(0, inFlight - 1);\n const status = String(res.statusCode);\n statuses.set(status, (statuses.get(status) ?? 0) + 1);\n });\n next();\n };\n\n const render = (): string => {\n const memory = process.memoryUsage();\n const lines = [\n '# HELP accessi_http_requests_total Richieste HTTP totali.',\n '# TYPE accessi_http_requests_total counter',\n ...[...statuses.entries()].map(\n ([status, count]) => `accessi_http_requests_total{status=\"${status}\"} ${count}`,\n ),\n '# HELP accessi_http_in_flight Richieste HTTP in corso.',\n '# TYPE accessi_http_in_flight gauge',\n `accessi_http_in_flight ${inFlight}`,\n '# HELP accessi_process_uptime_seconds Uptime del processo.',\n '# TYPE accessi_process_uptime_seconds gauge',\n `accessi_process_uptime_seconds ${Math.floor((Date.now() - startedAt) / 1000)}`,\n '# HELP accessi_process_memory_bytes Memoria del processo.',\n '# TYPE accessi_process_memory_bytes gauge',\n `accessi_process_memory_bytes{type=\"rss\"} ${memory.rss}`,\n `accessi_process_memory_bytes{type=\"heapUsed\"} ${memory.heapUsed}`,\n `accessi_process_memory_bytes{type=\"heapTotal\"} ${memory.heapTotal}`,\n '# HELP accessi_http_requests_started_total Richieste HTTP avviate.',\n '# TYPE accessi_http_requests_started_total counter',\n `accessi_http_requests_started_total ${requests}`,\n ];\n return `${lines.join('\\n')}\\n`;\n };\n\n return { middleware, render };\n}\n\nfunction collectHealthStores(options: AccessiOptions): Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> {\n const stores: Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> = [];\n const seen = new Set<unknown>();\n\n const add = (name: string, store: { healthCheck?: () => Promise<boolean> } | undefined): void => {\n if (!store || seen.has(store) || typeof store.healthCheck !== 'function') return;\n seen.add(store);\n stores.push({ name, store });\n };\n\n add('publicAuthRateLimit', options.publicAuthRateLimit?.store);\n add('serviceTokenRateLimit', options.serviceTokens?.rateLimitStore);\n add('consoleEntry', options.consoleEntry?.store);\n add('edgeRateLimit', options.edgeRateLimit?.store);\n add('sessionRevocation', options.sessionRevocation?.store);\n add('refreshTokenRotation', options.refreshTokenRotation?.store);\n return stores;\n}\n\nasync function checkDatabase(options: AccessiOptions): Promise<HealthCheckResult> {\n try {\n const version = await AccessiDatabaseUpdater.getCurrentVersion(options);\n if (!version) {\n return { ok: false, detail: 'schema Accessi non inizializzato' };\n }\n return {\n ok: true,\n detail: version === ACCESSI_SCHEMA_VERSION\n ? version\n : `${version} (atteso ${ACCESSI_SCHEMA_VERSION})`,\n };\n } catch (error) {\n return { ok: false, detail: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/**\n * Crea un servizio Accessi standalone con health, readiness, metriche e shutdown.\n *\n * Non apre la porta finche non viene chiamato `start()`.\n */\nexport async function createAccessiService(\n options: AccessiServiceOptions = {},\n): Promise<AccessiService> {\n const logger = new Logger('AccessiService');\n const accessiOptions = options.accessiOptions ?? createAccessiOptionsFromEnv();\n assertValidAccessiOptions(accessiOptions);\n for (const warning of validateAccessiOptions(accessiOptions).warnings) {\n logger.warning(`Configurazione Accessi: ${warning.code} - ${warning.message}`);\n }\n\n const app = options.app ?? express();\n const healthPath = normalizePath(options.healthPath ?? '/health');\n const metrics = createMetrics();\n const readinessChecks = options.readinessChecks ?? [];\n let initialized = false;\n let nestApp: AccessiModuleInitializationResult['nestApp'] | undefined;\n let document: AccessiModuleInitializationResult['document'] | undefined;\n let server: Server | undefined;\n let stopping = false;\n\n app.use(metrics.middleware);\n\n app.get(`${healthPath}/live`, (_req: Request, res: Response) => {\n res.status(200).json({\n status: 'ok',\n uptimeSeconds: Math.floor(process.uptime()),\n });\n });\n\n app.get(`${healthPath}/ready`, async (_req: Request, res: Response) => {\n if (!initialized || !nestApp) {\n res.status(503).json({\n status: 'error',\n checks: { bootstrap: { ok: false, detail: 'bootstrap non completato' } },\n });\n return;\n }\n\n const checks: Record<string, HealthCheckResult> = {\n bootstrap: { ok: true },\n database: await checkDatabase(accessiOptions),\n };\n\n const stores = collectHealthStores(accessiOptions);\n await Promise.all(stores.map(async ({ name, store }) => {\n try {\n checks[name] = { ok: Boolean(await store.healthCheck?.()) };\n } catch (error) {\n checks[name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }));\n\n for (const check of readinessChecks) {\n try {\n const ok = await check.check();\n checks[check.name] = { ok: Boolean(ok) };\n } catch (error) {\n checks[check.name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n const ok = Object.values(checks).every((check) => check.ok);\n res.status(ok ? 200 : 503).json({\n status: ok ? 'ok' : 'error',\n checks,\n timestamp: new Date().toISOString(),\n });\n });\n\n if (options.metrics !== false) {\n app.get(`${healthPath}/metrics`, (_req: Request, res: Response) => {\n res.setHeader('Content-Type', 'text/plain; version=0.0.4');\n res.status(200).send(metrics.render());\n });\n }\n\n const result = await initializeAccessiModule(app, accessiOptions);\n nestApp = result.nestApp;\n document = result.document;\n initialized = true;\n\n const stop = async (): Promise<void> => {\n if (stopping) return;\n stopping = true;\n const timeout = Math.max(1_000, options.shutdownTimeoutMs ?? 10_000);\n await Promise.race([\n new Promise<void>((resolve) => {\n if (!server) return resolve();\n server.close(() => resolve());\n }),\n new Promise<void>((resolve) => setTimeout(resolve, timeout)),\n ]);\n try {\n await nestApp?.close();\n } finally {\n await Orm.closePools();\n }\n };\n\n const start = async (): Promise<Server> => {\n if (server) return server;\n const port = options.port ?? Number(process.env.PORT ?? 3000);\n server = await new Promise<Server>((resolve, reject) => {\n const listener = options.host\n ? app.listen(port, options.host, () => resolve(listener))\n : app.listen(port, () => resolve(listener));\n listener.once('error', reject);\n });\n const address = server.address();\n const actualPort = typeof address === 'object' && address ? address.port : port;\n logger.info(`Accessi Service in ascolto su http://${options.host ?? '0.0.0.0'}:${actualPort}`);\n return server;\n };\n\n return {\n app,\n get nestApp() {\n if (!nestApp) throw new Error('Accessi Service non inizializzato.');\n return nestApp;\n },\n get document() {\n if (!document) throw new Error('Documento OpenAPI non disponibile.');\n return document;\n },\n start,\n stop,\n };\n}\n\n/**\n * Avvia Accessi Service e registra SIGTERM/SIGINT per lo shutdown graceful.\n */\nexport async function startAccessiService(options: AccessiServiceOptions = {}): Promise<AccessiService> {\n const service = await createAccessiService(options);\n await service.start();\n\n let shuttingDown = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n new Logger('AccessiService').info(`Ricevuto ${signal}: arresto in corso.`);\n await service.stop();\n };\n\n process.once('SIGTERM', () => { void shutdown('SIGTERM'); });\n process.once('SIGINT', () => { void shutdown('SIGINT'); });\n return service;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"standalone.js","sourceRoot":"","sources":["../../../src/accessi/server/standalone.ts"],"names":[],"mappings":"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","sourcesContent":["import express from 'express';\nimport type { Application, Request, Response } from 'express';\nimport type { Server } from 'http';\nimport { Logger } from '../../Logger';\nimport { Orm } from '../../Orm';\nimport { initializeAccessiModule } from '../../accessi-module';\nimport type {\n AccessiModuleInitializationResult,\n} from '../../accessi-module';\nimport type { AccessiOptions } from '../../accessi-module/AccessiModule';\nimport { createAccessiOptionsFromEnv } from '../../accessi-module/database-updates/accessiOptionsFromEnv';\nimport {\n ACCESSI_SCHEMA_VERSION,\n} from '../../accessi-module/database-updates/accessiSchema';\nimport { AccessiDatabaseUpdater } from '../../accessi-module/database-updates/AccessiDatabaseUpdater';\nimport { assertValidAccessiOptions, validateAccessiOptions } from '../../accessi-module/security/validateOptions';\n\nexport interface AccessiReadinessCheck {\n name: string;\n check: () => boolean | Promise<boolean>;\n}\n\nexport interface AccessiServiceOptions {\n /** Applicazione Express gia esistente. Default: nuova app. */\n app?: Application;\n /** Configurazione completa. Default: `createAccessiOptionsFromEnv()`. */\n accessiOptions?: AccessiOptions;\n port?: number;\n host?: string;\n /** Path base degli endpoint health. Default: `/health`. */\n healthPath?: string;\n /** Espone `/health/metrics` in formato Prometheus. Default: true. */\n metrics?: boolean;\n /** Check aggiuntivi per la readiness. */\n readinessChecks?: AccessiReadinessCheck[];\n /** Timeout chiusura server. Default: 10000 ms. */\n shutdownTimeoutMs?: number;\n}\n\nexport interface AccessiService {\n app: Application;\n nestApp: AccessiModuleInitializationResult['nestApp'];\n document: AccessiModuleInitializationResult['document'];\n start(): Promise<Server>;\n stop(): Promise<void>;\n}\n\ninterface HealthCheckResult {\n ok: boolean;\n detail?: string;\n}\n\nfunction normalizePath(value: string): string {\n return `/${value.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\nfunction createMetrics() {\n const startedAt = Date.now();\n let requests = 0;\n let inFlight = 0;\n const statuses = new Map<string, number>();\n\n const middleware = (_req: Request, res: Response, next: () => void): void => {\n requests += 1;\n inFlight += 1;\n res.on('finish', () => {\n inFlight = Math.max(0, inFlight - 1);\n const status = String(res.statusCode);\n statuses.set(status, (statuses.get(status) ?? 0) + 1);\n });\n next();\n };\n\n const render = (): string => {\n const memory = process.memoryUsage();\n const lines = [\n '# HELP accessi_http_requests_total Richieste HTTP totali.',\n '# TYPE accessi_http_requests_total counter',\n ...[...statuses.entries()].map(\n ([status, count]) => `accessi_http_requests_total{status=\"${status}\"} ${count}`,\n ),\n '# HELP accessi_http_in_flight Richieste HTTP in corso.',\n '# TYPE accessi_http_in_flight gauge',\n `accessi_http_in_flight ${inFlight}`,\n '# HELP accessi_process_uptime_seconds Uptime del processo.',\n '# TYPE accessi_process_uptime_seconds gauge',\n `accessi_process_uptime_seconds ${Math.floor((Date.now() - startedAt) / 1000)}`,\n '# HELP accessi_process_memory_bytes Memoria del processo.',\n '# TYPE accessi_process_memory_bytes gauge',\n `accessi_process_memory_bytes{type=\"rss\"} ${memory.rss}`,\n `accessi_process_memory_bytes{type=\"heapUsed\"} ${memory.heapUsed}`,\n `accessi_process_memory_bytes{type=\"heapTotal\"} ${memory.heapTotal}`,\n '# HELP accessi_http_requests_started_total Richieste HTTP avviate.',\n '# TYPE accessi_http_requests_started_total counter',\n `accessi_http_requests_started_total ${requests}`,\n ];\n return `${lines.join('\\n')}\\n`;\n };\n\n return { middleware, render };\n}\n\nfunction collectHealthStores(options: AccessiOptions): Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> {\n const stores: Array<{ name: string; store: { healthCheck?: () => Promise<boolean> } }> = [];\n const seen = new Set<unknown>();\n\n const add = (name: string, store: { healthCheck?: () => Promise<boolean> } | undefined): void => {\n if (!store || seen.has(store) || typeof store.healthCheck !== 'function') return;\n seen.add(store);\n stores.push({ name, store });\n };\n\n add('publicAuthRateLimit', options.publicAuthRateLimit?.store);\n add('serviceTokenRateLimit', options.serviceTokens?.rateLimitStore);\n add('consoleEntry', options.consoleEntry?.store);\n add('edgeRateLimit', options.edgeRateLimit?.store);\n add('sessionRevocation', options.sessionRevocation?.store);\n add('accessTokenRevocation', options.accessTokenRevocation?.store);\n add('refreshTokenRotation', options.refreshTokenRotation?.store);\n return stores;\n}\n\nasync function checkDatabase(options: AccessiOptions): Promise<HealthCheckResult> {\n try {\n const version = await AccessiDatabaseUpdater.getCurrentVersion(options);\n if (!version) {\n return { ok: false, detail: 'schema Accessi non inizializzato' };\n }\n return {\n ok: true,\n detail: version === ACCESSI_SCHEMA_VERSION\n ? version\n : `${version} (atteso ${ACCESSI_SCHEMA_VERSION})`,\n };\n } catch (error) {\n return { ok: false, detail: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/**\n * Crea un servizio Accessi standalone con health, readiness, metriche e shutdown.\n *\n * Non apre la porta finche non viene chiamato `start()`.\n */\nexport async function createAccessiService(\n options: AccessiServiceOptions = {},\n): Promise<AccessiService> {\n const logger = new Logger('AccessiService');\n const accessiOptions = options.accessiOptions ?? createAccessiOptionsFromEnv();\n assertValidAccessiOptions(accessiOptions);\n for (const warning of validateAccessiOptions(accessiOptions).warnings) {\n logger.warning(`Configurazione Accessi: ${warning.code} - ${warning.message}`);\n }\n\n const app = options.app ?? express();\n const healthPath = normalizePath(options.healthPath ?? '/health');\n const metrics = createMetrics();\n const readinessChecks = options.readinessChecks ?? [];\n let initialized = false;\n let nestApp: AccessiModuleInitializationResult['nestApp'] | undefined;\n let document: AccessiModuleInitializationResult['document'] | undefined;\n let server: Server | undefined;\n let stopping = false;\n\n app.use(metrics.middleware);\n\n app.get(`${healthPath}/live`, (_req: Request, res: Response) => {\n res.status(200).json({\n status: 'ok',\n uptimeSeconds: Math.floor(process.uptime()),\n });\n });\n\n app.get(`${healthPath}/ready`, async (_req: Request, res: Response) => {\n if (!initialized || !nestApp) {\n res.status(503).json({\n status: 'error',\n checks: { bootstrap: { ok: false, detail: 'bootstrap non completato' } },\n });\n return;\n }\n\n const checks: Record<string, HealthCheckResult> = {\n bootstrap: { ok: true },\n database: await checkDatabase(accessiOptions),\n };\n\n const stores = collectHealthStores(accessiOptions);\n await Promise.all(stores.map(async ({ name, store }) => {\n try {\n checks[name] = { ok: Boolean(await store.healthCheck?.()) };\n } catch (error) {\n checks[name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }));\n\n for (const check of readinessChecks) {\n try {\n const ok = await check.check();\n checks[check.name] = { ok: Boolean(ok) };\n } catch (error) {\n checks[check.name] = {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n const ok = Object.values(checks).every((check) => check.ok);\n res.status(ok ? 200 : 503).json({\n status: ok ? 'ok' : 'error',\n checks,\n timestamp: new Date().toISOString(),\n });\n });\n\n if (options.metrics !== false) {\n app.get(`${healthPath}/metrics`, (_req: Request, res: Response) => {\n res.setHeader('Content-Type', 'text/plain; version=0.0.4');\n res.status(200).send(metrics.render());\n });\n }\n\n const result = await initializeAccessiModule(app, accessiOptions);\n nestApp = result.nestApp;\n document = result.document;\n initialized = true;\n\n const stop = async (): Promise<void> => {\n if (stopping) return;\n stopping = true;\n const timeout = Math.max(1_000, options.shutdownTimeoutMs ?? 10_000);\n await Promise.race([\n new Promise<void>((resolve) => {\n if (!server) return resolve();\n server.close(() => resolve());\n }),\n new Promise<void>((resolve) => setTimeout(resolve, timeout)),\n ]);\n try {\n await nestApp?.close();\n } finally {\n await Orm.closePools();\n }\n };\n\n const start = async (): Promise<Server> => {\n if (server) return server;\n const port = options.port ?? Number(process.env.PORT ?? 3000);\n server = await new Promise<Server>((resolve, reject) => {\n const listener = options.host\n ? app.listen(port, options.host, () => resolve(listener))\n : app.listen(port, () => resolve(listener));\n listener.once('error', reject);\n });\n const address = server.address();\n const actualPort = typeof address === 'object' && address ? address.port : port;\n logger.info(`Accessi Service in ascolto su http://${options.host ?? '0.0.0.0'}:${actualPort}`);\n return server;\n };\n\n return {\n app,\n get nestApp() {\n if (!nestApp) throw new Error('Accessi Service non inizializzato.');\n return nestApp;\n },\n get document() {\n if (!document) throw new Error('Documento OpenAPI non disponibile.');\n return document;\n },\n start,\n stop,\n };\n}\n\n/**\n * Avvia Accessi Service e registra SIGTERM/SIGINT per lo shutdown graceful.\n */\nexport async function startAccessiService(options: AccessiServiceOptions = {}): Promise<AccessiService> {\n const service = await createAccessiService(options);\n await service.start();\n\n let shuttingDown = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n new Logger('AccessiService').info(`Ricevuto ${signal}: arresto in corso.`);\n await service.stop();\n };\n\n process.once('SIGTERM', () => { void shutdown('SIGTERM'); });\n process.once('SIGINT', () => { void shutdown('SIGINT'); });\n return service;\n}\n"]}
|
|
@@ -13,6 +13,7 @@ import type { ConsoleEntryStore } from './security/consoleEntry';
|
|
|
13
13
|
import type { RateLimitStore } from './security/rateLimitStore';
|
|
14
14
|
import type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';
|
|
15
15
|
import type { SessionRevocationOptions } from './security/sessionRevocation';
|
|
16
|
+
import type { AccessTokenRevocationOptions } from './security/accessTokenRevocation';
|
|
16
17
|
import type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';
|
|
17
18
|
/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */
|
|
18
19
|
export interface JwtOptions {
|
|
@@ -253,7 +254,9 @@ export interface AccessiOptions {
|
|
|
253
254
|
http?: AccessiHttpOptions;
|
|
254
255
|
/** Revoca sessioni per utente tramite store memory/Redis. */
|
|
255
256
|
sessionRevocation?: SessionRevocationOptions;
|
|
256
|
-
/**
|
|
257
|
+
/** Revoca dei singoli access token tramite `jti`, memory/Redis. */
|
|
258
|
+
accessTokenRevocation?: AccessTokenRevocationOptions;
|
|
259
|
+
/** Refresh token monouso tramite rotazione memory/Redis; rileva il riuso e revoca la famiglia. */
|
|
257
260
|
refreshTokenRotation?: RefreshTokenRotationOptions;
|
|
258
261
|
}
|
|
259
262
|
export declare class AccessiModule {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAS/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,sGAAmG;AACnG,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,4DAAuE;AACvE,sEAAsE;AAuR/D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B;aAAC;YAC7F,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AA9CY,sCAAa;wBAAb,aAAa;IApBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,iEAA+B;YAC/B,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;SAC/B;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B,CAAC;QACnU,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CA8CzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { INestApplication, LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm } from './security/jwtTokenOptions';\nimport type { ConsoleEntryStore } from './security/consoleEntry';\nimport type { RateLimitStore } from './security/rateLimitStore';\nimport type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';\nimport type { SessionRevocationOptions } from './security/sessionRevocation';\nimport type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { FederatedAuthExchangeController } from './federated-auth/FederatedAuthExchangeController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { AccessiJwksBootstrapService } from './security/jwksBootstrap';\nimport { assertEmailConfigured } from './security/emailConfiguration';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */\n jwksPath?: string;\n /** Chiavi pubbliche precedenti, esposte in JWKS durante la rotazione. */\n previousPublicKeys?: Array<{\n publicKey: string;\n keyId: string;\n algorithm?: AccessiAccessTokenAlgorithm;\n }>;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n /**\n * Durata del refresh token. Se assente il refresh token non viene emesso.\n * Consigliato: `30d`.\n */\n refreshExpiresIn?: string;\n}\n\n/** Configurazione dei ticket di ingresso alla console. */\nexport interface ConsoleEntryOptions {\n /** Durata del ticket in millisecondi. Default 60000. */\n ttlMs?: number;\n /** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */\n store?: ConsoleEntryStore;\n}\n\n/** Impostazioni HTTP del servizio Accessi. */\nexport interface AccessiHttpOptions {\n /** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */\n cors?: Parameters<INestApplication['enableCors']>[0] | false;\n /** Trust proxy per IP reali dietro load balancer/reverse proxy. */\n trustProxy?: boolean | number | string;\n /** Header di sicurezza di base su console/OpenAPI. Default: true. */\n securityHeaders?: boolean;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n /** Store condiviso (es. Redis). Default: memoria del processo. */\n store?: RateLimitStore;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n refresh?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n /** Store condiviso per il rate limit dei service token. Default: memoria. */\n rateLimitStore?: RateLimitStore;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /** Base URL API per la console quando UI e API sono su domini diversi. */\n consoleApiBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n /** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */\n consoleEntry?: ConsoleEntryOptions;\n /** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */\n edgeRateLimit?: AccessiEdgeRateLimitOptions;\n /** CORS, trust proxy e header di sicurezza del servizio. */\n http?: AccessiHttpOptions;\n /** Revoca sessioni per utente tramite store memory/Redis. */\n sessionRevocation?: SessionRevocationOptions;\n /** Refresh token monouso tramite rotazione memory/Redis. */\n refreshTokenRotation?: RefreshTokenRotationOptions;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n FederatedAuthExchangeController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccessiModule.js","sourceRoot":"","sources":["../../src/accessi-module/AccessiModule.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAgF;AAQhF,2CAA+D;AAU/D,oEAAiE;AACjE,uEAAoE;AACpE,sFAAmF;AACnF,oEAAiE;AACjE,mEAAgE;AAChE,iEAA8D;AAC9D,6EAA0E;AAC1E,iEAA8D;AAC9D,0EAAuE;AACvE,qEAAkE;AAClE,iFAA8E;AAC9E,4FAAyF;AACzF,qDAAoD;AACpD,kEAAsE;AACtE,sFAAmF;AACnF,gFAA6E;AAC7E,sFAAmF;AACnF,sGAAmG;AACnG,qFAAkF;AAClF,iFAA8E;AAC9E,iFAA8E;AAC9E,4FAAyF;AACzF,oEAAiE;AACjE,qEAAkE;AAClE,iGAA8F;AAC9F,4FAAyF;AACzF,kGAA+F;AAC/F,4DAAuE;AACvE,sEAAsE;AAyR/D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAuB;QACpC,yFAAyF;QACzF,IAAA,0CAAqB,EAAC,OAAO,CAAC,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,iBAAiB;oBAC1B,QAAQ,EAAE,OAAO;iBAClB;gBACD,yBAAW;gBACX,mCAAgB;gBAChB,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,+CAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B;aAAC;YAC7F,OAAO,EAAE;gBACP,iBAAiB;gBACjB,yBAAW;gBACX,yBAAW;gBACX,2BAAY;gBACZ,qCAAiB;gBACjB,6BAAa;gBACb,yCAAmB;gBACnB,6BAAc;gBACd,wCAAsB;gBACtB,2CAAoB;gBACpB,yCAAmB;gBACnB,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB;aAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAA;AA9CY,sCAAa;wBAAb,aAAa;IApBzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,WAAW,EAAE;YACX,iCAAe;YACf,+BAAc;YACd,2CAAoB;YACpB,+BAAc;YACd,mCAAgB;YAChB,+CAAsB;YACtB,iDAAuB;YACvB,mDAAwB;YACxB,+CAAsB;YACtB,iEAA+B;YAC/B,+CAAsB;YACtB,mCAAgB;YAChB,+DAA8B;SAC/B;QACD,SAAS,EAAE,CAAC,yBAAW,EAAE,mCAAgB,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,+CAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,EAAE,2CAA2B,CAAC;QACnU,OAAO,EAAE,CAAC,yBAAW,EAAE,yBAAW,EAAE,2BAAY,EAAE,qCAAiB,EAAE,6BAAa,EAAE,yCAAmB,EAAE,6BAAc,EAAE,wCAAsB,EAAE,2CAAoB,EAAE,yCAAmB,EAAE,qCAAiB,EAAE,yCAAmB,EAAE,6CAAqB,CAAC;KAC3P,CAAC;GACW,aAAa,CA8CzB","sourcesContent":["import { TwoFactorService } from './Services/TwoFactorService/TwoFactorService';\n/**\n * Modulo che gestisce le operazioni di accesso degli utenti, incluse le rotte, il controller e il modello.\n *\n * @module AccessiModule\n * @author mttdev382\n */\nimport { Options } from 'node-firebird';\nimport { DynamicModule, Global, Module } from '@nestjs/common';\nimport type { INestApplication, LoggerService } from '@nestjs/common';\nimport type { OpenApiSetupOptions } from '../openapi/OpenApiConfig';\nimport type { AccessiAccessTokenAlgorithm } from './security/jwtTokenOptions';\nimport type { ConsoleEntryStore } from './security/consoleEntry';\nimport type { RateLimitStore } from './security/rateLimitStore';\nimport type { AccessiEdgeRateLimitOptions } from './security/edgeRateLimit';\nimport type { SessionRevocationOptions } from './security/sessionRevocation';\nimport type { AccessTokenRevocationOptions } from './security/accessTokenRevocation';\nimport type { RefreshTokenRotationOptions } from './security/refreshTokenRotation';\nimport { AuthService } from './Services/AuthService/AuthService';\nimport { EmailService } from './Services/EmailService/EmailService';\nimport { PermissionService } from './Services/PermissionService/PermissionService';\nimport { UserService } from './Services/UserService/UserService';\nimport { EmailController } from './Controllers/EmailController';\nimport { AuthController } from './Controllers/AuthController';\nimport { PermissionController } from './Controllers/PermissionController';\nimport { UserController } from './Controllers/UserController';\nimport { FiltriService } from './Services/FiltriService/FiltriService';\nimport { FiltriController } from './Controllers/FiltriController';\nimport { ConfiguratorController } from './Controllers/ConfiguratorController';\nimport { ConfiguratorService } from './Services/ConfiguratorService/ConfiguratorService';\nimport { JwtSimpleGuard } from './jwt/jwt.strategy';\nimport { AuthenticateGenService } from './middleware/authenticateGen';\nimport { AccessiDatabaseUpdater } from './database-updates/AccessiDatabaseUpdater';\nimport { FederatedAuthService } from './federated-auth/FederatedAuthService';\nimport { FederatedAuthController } from './federated-auth/FederatedAuthController';\nimport { FederatedAuthExchangeController } from './federated-auth/FederatedAuthExchangeController';\nimport { AccessiConsoleController } from './Controllers/AccessiConsoleController';\nimport { ConsoleEntryController } from './Controllers/ConsoleEntryController';\nimport { ServiceTokenController } from './Controllers/ServiceTokenController';\nimport { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';\nimport { ServiceTokenGuard } from './security/serviceTokenGuard';\nimport { SchemaController } from './Controllers/SchemaController';\nimport { AccessiIntrospectionController } from './Controllers/AccessiIntrospectionController';\nimport { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';\nimport { AdminBootstrapService } from './Services/AdminBootstrapService/AdminBootstrapService';\nimport { AccessiJwksBootstrapService } from './security/jwksBootstrap';\nimport { assertEmailConfigured } from './security/emailConfiguration';\n\n/** JWT emesso da Accessi dopo un login locale o SSO. Non riutilizzare il segreto del provider SSO. */\nexport interface JwtOptions {\n /** Segreto simmetrico per firmare e verificare i JWT Accessi; deve essere unico per ambiente. */\n secret: string;\n /** Issuer (`iss`) opzionale degli access token. Consigliato in una topologia multi-servizio. */\n issuer?: string;\n /** Audience (`aud`) opzionale degli access token. */\n audience?: string | string[];\n /** Algoritmo degli access token. Default `HS256` per retrocompatibilita. */\n algorithm?: AccessiAccessTokenAlgorithm;\n /** Chiave privata PEM per RS/ES. Obbligatoria quando `algorithm` non e HS*. */\n privateKey?: string;\n /** Chiave pubblica PEM per la verifica RS/ES. */\n publicKey?: string;\n /** Key id pubblicato nella JWKS, per rotazione chiavi. */\n keyId?: string;\n /** Path pubblico della JWKS. Default `accessi/.well-known/jwks.json` con algoritmi asimmetrici. */\n jwksPath?: string;\n /** Chiavi pubbliche precedenti, esposte in JWKS durante la rotazione. */\n previousPublicKeys?: Array<{\n publicKey: string;\n keyId: string;\n algorithm?: AccessiAccessTokenAlgorithm;\n }>;\n /** Durata compatibile con `jsonwebtoken`, per esempio `24h` o `3600s`. */\n expiresIn: string;\n /**\n * Durata del refresh token. Se assente il refresh token non viene emesso.\n * Consigliato: `30d`.\n */\n refreshExpiresIn?: string;\n}\n\n/** Configurazione dei ticket di ingresso alla console. */\nexport interface ConsoleEntryOptions {\n /** Durata del ticket in millisecondi. Default 60000. */\n ttlMs?: number;\n /** Store condiviso (es. Redis) per deployment multi-istanza. Default: memoria. */\n store?: ConsoleEntryStore;\n}\n\n/** Impostazioni HTTP del servizio Accessi. */\nexport interface AccessiHttpOptions {\n /** Opzioni CORS Nest. `false` disabilita CORS. Default: exposedHeaders ['X-Total-Count']. */\n cors?: Parameters<INestApplication['enableCors']>[0] | false;\n /** Trust proxy per IP reali dietro load balancer/reverse proxy. */\n trustProxy?: boolean | number | string;\n /** Header di sicurezza di base su console/OpenAPI. Default: true. */\n securityHeaders?: boolean;\n}\n\n/** Parametri SMTP usati esclusivamente per impostazione e reset della password. */\nexport interface EmailOptions {\n host: string;\n port: number;\n secure: boolean;\n requireTLS : boolean;\n tls: {\n rejectUnauthorized: boolean,\n }\n from: string;\n auth: {\n user: string;\n pass: string;\n };\n}\n\n/** Configura campi applicativi aggiuntivi restituiti insieme al profilo Accessi. */\nexport interface ExtensionFieldsOptions {\n /** Connessione al database contenente la tabella estesa. */\n databaseOptions: Options;\n /** Chiave con cui i dati saranno esposti nella risposta. */\n objectKey: string;\n /** Tabella applicativa contenente i dati estesi. */\n tableName: string;\n /** Colonne consentite; non valorizzarle mai con input HTTP. */\n tableFields: string[];\n /** Colonna correlata a `UTENTI.CODUTE`. */\n tableJoinFieldName: string;\n}\n\n/** Limite per una singola categoria di endpoint pubblici. */\nexport interface PublicAuthRateLimitRuleOptions {\n windowMs: number;\n maxAttempts: number;\n}\n\n/** Protezione degli endpoint pubblici. Default in memoria; in cluster usare uno store condiviso. */\nexport interface PublicAuthRateLimitOptions {\n enabled?: boolean;\n /** Store condiviso (es. Redis). Default: memoria del processo. */\n store?: RateLimitStore;\n login?: PublicAuthRateLimitRuleOptions;\n register?: PublicAuthRateLimitRuleOptions;\n passwordResetEmail?: PublicAuthRateLimitRuleOptions;\n passwordResetConfirm?: PublicAuthRateLimitRuleOptions;\n refresh?: PublicAuthRateLimitRuleOptions;\n getUserByToken?: PublicAuthRateLimitRuleOptions;\n twoFactorVerify?: PublicAuthRateLimitRuleOptions;\n twoFactorResend?: PublicAuthRateLimitRuleOptions;\n adminBootstrap?: PublicAuthRateLimitRuleOptions;\n consoleEntry?: PublicAuthRateLimitRuleOptions;\n}\n\n/**\n * Bootstrap del primo admin. Se abilitato, Accessi genera un token casuale a ogni avvio del\n * processo, lo stampa nel log e lo accetta sull'endpoint pubblico `POST /accessi/auth/bootstrap-admin`.\n * Serve a creare il primo utente admin senza email di conferma e senza un admin gia esistente.\n */\nexport interface AdminBootstrapOptions {\n /** Abilita il bootstrap admin. Default `false`. */\n enabled?: boolean;\n /** Crea l'utente come superutente oltre che admin. Default `true`. */\n superUser?: boolean;\n}\n\n/** Controls the legacy public username/password registration endpoint. Disabled by default. */\nexport interface PublicRegistrationOptions {\n /** Enables POST /accessi/user/register. Applications that used it before must opt in explicitly. */\n enabled?: boolean;\n}\n\n/** Configurazione dei token di servizio (macchina-a-macchina, senza utente). */\nexport interface ServiceTokenOptions {\n /** Abilita gli endpoint amministrativi dei service token. Default `true`. */\n enabled?: boolean;\n /** Durata predefinita in giorni quando non e indicata una scadenza esplicita. Default: nessuna scadenza. */\n defaultTtlDays?: number;\n /** Store condiviso per il rate limit dei service token. Default: memoria. */\n rateLimitStore?: RateLimitStore;\n}\n\n/** Cosa fare quando uno script gia applicato presenta un checksum diverso (file modificato). */\nexport type CatalogScriptChecksumPolicy = 'error' | 'warn' | 'reapply';\n\n/**\n * Catalog migrations applicative (menu, ruoli, tipi, cataloghi). Gli script `.sql` vivono nel\n * backend ospitante (versionati in repository) e vengono eseguiti da Accessi dopo la\n * riconciliazione dello schema. Ogni script e tracciato nella tabella `ACCESSI_CATALOG_SCRIPT`,\n * quindi viene applicato una sola volta per database (idempotenza lato DB).\n */\nexport interface SystemSeedsOptions {\n /** `false` disabilita il seed automatico, ad esempio per ambienti gestiti manualmente. */\n enabled?: boolean;\n}\n\nexport interface CatalogScriptsOptions {\n /** Abilita l'esecuzione automatica al bootstrap. Default `false`. */\n enabled?: boolean;\n /** Cartella contenente gli script `.sql` (assoluta o relativa alla working directory). */\n folder: string;\n /** Cosa fare se il checksum di uno script applicato e cambiato. Default `error`. */\n onChecksumMismatch?: CatalogScriptChecksumPolicy;\n /** Se `true` (default) un errore interrompe l'esecuzione e non avanza allo script successivo. */\n stopOnError?: boolean;\n /** Globi/estensioni inclusi. Default: tutti i `.sql`. */\n include?: string[];\n /** Numero massimo di script eseguiti in un singolo run (protezione operativa). Default: illimitato. */\n maxScriptsPerRun?: number;\n /**\n * Permette statement DDL/schema negli script. Default `false`: le catalog migrations possono\n * modificare solo righe. Sconsigliato: lo schema e di competenza di `db:update:accessi`.\n */\n allowDdl?: boolean;\n}\n\n/**\n * Enables Accessi's provider-agnostic federated identity capability.\n *\n * Accessi never validates Azure, Google, Apple, SAML, or other provider tokens.\n * The hosting backend must validate its own SSO flow and pass only a verified\n * `{ provider, subject }` identity to FederatedAuthService.\n */\nexport interface FederatedAuthenticationOptions {\n /** Attiva le API SSO generiche; con `false` il comportamento password storico rimane invariato. */\n enabled?: boolean;\n /** @deprecated Schema management is centralized in autoUpdateDatabase. This legacy flag no longer starts separate SSO migrations. */\n autoUpdateSchema?: boolean;\n /** Allows a backend to create a user from a verified external identity without a master user. Default false. */\n allowSelfRegistration?: boolean;\n}\n\n/**\n * Configurazione completa del modulo Accessi, fornita esclusivamente dal backend ospitante.\n * Segreti JWT, SMTP, database e le configurazioni tecniche dei provider SSO non devono mai raggiungere il browser.\n */\nexport interface AccessiOptions {\n /** Connessione Firebird alla base dati Accessi. */\n databaseOptions: Options;\n /**\n * Basepath del sito es: 'http://www.il-mio-sito.it/nome-progetto(se c'è)'\n */\n confirmationEmailUrl: string;\n /**\n * Percorso della pagina di reset personalizzata es. http://localhost:4200/#/admin/reset-password\n * N.B si sostituisce al confirmationMailURl\n */\n customResetPage?: string;\n /** URL di ritorno della pagina standard di reset dopo il completamento. */\n confirmationEmailReturnUrl: string;\n /** Prefisso applicativo facoltativo trasmesso alla pagina standard di reset. */\n confirmationEmailPrefix?: string;\n /** Chiave riservata alla compatibilita e alla migrazione delle password legacy cifrate. */\n encryptionKey: string;\n /** Abilita gli utenti fittizi `admin` e `demo` solo fuori produzione. */\n mockDemoUser: boolean;\n /** Attiva il controllo della scadenza password durante il login locale. */\n passwordExpiration?: boolean;\n /** Giorni di validita della password; quando assente Accessi usa 90 giorni. */\n passwordExpirationDays?: number;\n /** Esegue al bootstrap la conversione non distruttiva delle password legacy. Default `true`. */\n legacyPasswordMigrationOnStartup?: boolean;\n /** Riconcilia lo schema al bootstrap (default `true`). Con `false` verifica comunque la compatibilita in sola lettura e blocca avvii incompatibili. */\n autoUpdateDatabase?: boolean;\n /** Parametri JWT dei token emessi da Accessi. */\n jwtOptions: JwtOptions;\n /** Parametri SMTP per reset e attivazione password. */\n emailOptions: EmailOptions;\n publicAuthRateLimit?: PublicAuthRateLimitOptions;\n /** Public local registration is deliberately opt-in. Existing applications must set enabled: true to retain it. */\n publicRegistration?: PublicRegistrationOptions;\n /** Optional provider-agnostic SSO support. Provider-specific configuration remains in the hosting backend. */\n federatedAuthentication?: FederatedAuthenticationOptions;\n extensionFieldsOptions?: ExtensionFieldsOptions[];\n /** Token di servizio per chiamate tecniche macchina-a-macchina. Abilitati di default. */\n serviceTokens?: ServiceTokenOptions;\n /** Catalog migrations applicative eseguite dopo la riconciliazione dello schema. */\n catalogScripts?: CatalogScriptsOptions;\n /** Seed di sistema eseguiti dopo la riconciliazione dello schema. Default: abilitati. */\n systemSeeds?: SystemSeedsOptions;\n /** Bootstrap del primo admin tramite token casuale stampato a ogni avvio. */\n adminBootstrap?: AdminBootstrapOptions;\n /** Base URL pubblica usata solo per loggare gli indirizzi (console, OpenAPI, API). */\n publicBaseUrl?: string;\n /** Base URL API per la console quando UI e API sono su domini diversi. */\n consoleApiBaseUrl?: string;\n /**\n * Documentazione OpenAPI del modulo. Default invariati:\n * UI `accessi/openapi`, JSON `accessi/openapi.json`.\n */\n openapi?: OpenApiSetupOptions;\n /** Logger Nest usato dal sotto-app Accessi. Se assente Nest usa il proprio logger. */\n logger?: LoggerService;\n /** Buffer dei log di bootstrap del sotto-app. Default `true` (comportamento storico). */\n bufferLogs?: boolean;\n /** Ticket di ingresso console: TTL e store condiviso per deployment multi-istanza. */\n consoleEntry?: ConsoleEntryOptions;\n /** Limite grossolano per IP davanti alle rotte Accessi. Opzionale. */\n edgeRateLimit?: AccessiEdgeRateLimitOptions;\n /** CORS, trust proxy e header di sicurezza del servizio. */\n http?: AccessiHttpOptions;\n /** Revoca sessioni per utente tramite store memory/Redis. */\n sessionRevocation?: SessionRevocationOptions;\n /** Revoca dei singoli access token tramite `jti`, memory/Redis. */\n accessTokenRevocation?: AccessTokenRevocationOptions;\n /** Refresh token monouso tramite rotazione memory/Redis; rileva il riuso e revoca la famiglia. */\n refreshTokenRotation?: RefreshTokenRotationOptions;\n}\n\n@Global()\n@Module({\n controllers: [\n EmailController,\n AuthController,\n PermissionController,\n UserController,\n FiltriController,\n ConfiguratorController,\n FederatedAuthController,\n AccessiConsoleController,\n ConsoleEntryController,\n FederatedAuthExchangeController,\n ServiceTokenController,\n SchemaController,\n AccessiIntrospectionController,\n ],\n providers: [AuthService, TwoFactorService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, AccessiDatabaseUpdater, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [AuthService, UserService, EmailService, PermissionService, FiltriService, ConfiguratorService, JwtSimpleGuard, AuthenticateGenService, FederatedAuthService, ServiceTokenService, ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n})\nexport class AccessiModule {\n /**\n * Registra Accessi nel contenitore Nest del backend ospitante.\n *\n * Usare questo metodo una sola volta nella composizione dell'applicazione. Per un backend\n * Express esistente usare invece `initializeAccessiModule`, che crea e monta l'host Nest interno.\n * La configurazione viene registrata con il token DI `ACCESSI_OPTIONS` ed e condivisa dai servizi.\n */\n static forRoot(options: AccessiOptions): DynamicModule {\n // Il servizio email e obbligatorio: reset password, 2FA e creazione utente ne dipendono.\n assertEmailConfigured(options);\n return {\n module: AccessiModule,\n providers: [\n {\n provide: 'ACCESSI_OPTIONS',\n useValue: options,\n },\n AuthService,\n TwoFactorService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n AccessiDatabaseUpdater,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService, AccessiJwksBootstrapService],\n exports: [\n 'ACCESSI_OPTIONS',\n AuthService,\n UserService,\n EmailService,\n PermissionService,\n FiltriService,\n ConfiguratorService,\n JwtSimpleGuard,\n AuthenticateGenService,\n FederatedAuthService,\n ServiceTokenService,\n ServiceTokenGuard, SchemaExportService, AdminBootstrapService],\n };\n }\n}\n"]}
|
|
@@ -1058,7 +1058,8 @@ var WIKI_SECTIONS = [
|
|
|
1058
1058
|
["openapi", "OpenApiSetupOptions", "no", "Path, titolo, descrizione e enabled della documentazione OpenAPI. Default invariati."],
|
|
1059
1059
|
["consoleEntry", "{ ttlMs, store }", "no", "TTL e store condiviso dei ticket console (Redis per multi-istanza). Default in memoria."],
|
|
1060
1060
|
["sessionRevocation", "{ enabled, store, ttlMs }", "no", "Revoca sessioni per utente tramite store memory/Redis; abilita POST /api/accessi/auth/revoke-sessions."],
|
|
1061
|
-
["
|
|
1061
|
+
["accessTokenRevocation", "{ enabled, store, ttlMs }", "no", "Revoca dei singoli access token tramite jti (memory/Redis); abilita POST /api/accessi/auth/revoke-token."],
|
|
1062
|
+
["refreshTokenRotation", "{ enabled, store, reuseGraceMs, revokeUserSessionsOnReuse }", "no", "Refresh token monouso tramite store memory/Redis; al riuso oltre la finestra di grazia revoca la famiglia di token. Consigliato in multi-istanza."],
|
|
1062
1063
|
["logger", "LoggerService", "no", "Logger Nest del sotto-app; se assente Nest usa il proprio logger."],
|
|
1063
1064
|
["bufferLogs", "boolean", "no", "Buffer dei log di bootstrap del sotto-app. Default true."]
|
|
1064
1065
|
]
|
|
@@ -1344,7 +1345,8 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1344
1345
|
note("warn", `Fail closed`, `Se introspection e configurata ma non raggiungibile, il resource server risponde 503. Non autorizza la richiesta.`),
|
|
1345
1346
|
note("info", `Introspection`, `POST /api/accessi/auth/introspect restituisce active=false per token invalido, scaduto o utente disabilitato. I risultati attivi sono cachati lato resource server per 30 secondi per default.`),
|
|
1346
1347
|
note("info", `JWKS`, `Con RS256/ES256 Accessi pubblica la JWKS su /accessi/.well-known/jwks.json (configurabile con jwtOptions.jwksPath). Il resource server puo usare jwks.url e ruotare le chiavi con previousPublicKeys.`),
|
|
1347
|
-
note("info", `
|
|
1348
|
+
note("info", `Revoca`, `revocation.store applica la revoca per utente; revocation.accessTokenStore rifiuta i singoli jti revocati e revocation.familyStore invalida le famiglie di refresh token revocate per riuso sospetto.`),
|
|
1349
|
+
note("info", `Audit`, `I fallimenti di autenticazione del resource server, i blocchi edge, il riuso dei refresh token e le revoche di sessione producono eventi strutturati tramite auditAccessi; i token e i segreti vengono redatti dal Logger.`)
|
|
1348
1350
|
]
|
|
1349
1351
|
},
|
|
1350
1352
|
// -------------------------------------------------------------------------
|
|
@@ -1692,7 +1694,7 @@ Authorization: Bearer <jwt amministratore>
|
|
|
1692
1694
|
table(
|
|
1693
1695
|
["Area", "Endpoint principali"],
|
|
1694
1696
|
[
|
|
1695
|
-
["Auth", "POST auth/login, auth/get-user-by-token, auth/confirm-reset-password/:token, auth/two-factor/verify, auth/two-factor/resend"],
|
|
1697
|
+
["Auth", "POST auth/login, auth/get-user-by-token, auth/confirm-reset-password/:token, auth/refresh, auth/revoke-sessions, auth/revoke-token, auth/two-factor/verify, auth/two-factor/resend"],
|
|
1696
1698
|
["Email", "POST email/send-reset-password-email, GET email/reset-password-page/:token"],
|
|
1697
1699
|
["Utenti", "GET user/get-users, POST user/create-managed-user, PUT user/update-user/:codiceUtente, DELETE user/delete-user/:codiceUtente, DELETE user/delete-user-permanent/:codiceUtente, POST user/set-password/:codiceUtente, POST user/set-stato, PATCH user/set-gdpr/:codiceUtente, POST user/register, POST user/login-as/:codiceUtente"],
|
|
1698
1700
|
["Permessi", "GET permission/roles, POST permission/create-role, PUT permission/update-role/:codiceRuolo, DELETE permission/delete-role/:codiceRuolo, POST permission/assign-roles/:codiceUtente, POST permission/assign-permissions/:codiceUtente, GET permission/grants/:codiceUtente, GET permission/menus, GET permission/menu-types, GET permission/groups-with-menus"],
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Accessi API
|
|
5
5
|
* OpenAPI spec version: 1.0
|
|
6
6
|
*/
|
|
7
|
-
import type { ActionResponse, AdminBootstrapStatusResponse, AssignPermissionsToUserRequest, AssignRolesToUserRequest, BootstrapAdminRequest, BootstrapAdminResponse, ConfirmResetPasswordRequest, ConsoleEntryExchangeRequest, ConsoleEntrySessionResponse, ConsoleEntryTicketResponse, CreateFederatedIdentityRequest, CreateFederatedProviderRequest, CreateFederatedUserRequest, CreateFilterTypeRequest, CreateMenuGroupRequest, CreateMenuRequest, CreateMenuTypeRequest, CreateScopeRequest, CreateServiceTokenRequest, CreateServiceTokenResponse, ErrorResponse, ExchangeFederatedIdentityRequest, FederatedExchangeResponse, FederatedIdentityListResponse, FederatedIdentityResponse, FederatedProviderListResponse, FederatedProviderResponse, FiltriUtente, GetFiltriResponse, GetFiltriUtenteParams, GetFiltriUtenteResponse, GetGroupsWithMenusParams, GetGroupsWithMenusResponse, GetMenuScopesResponse, GetMenuTypesResponse, GetMenusParams, GetMenusResponse, GetRolesResponse, GetSchemaResponse, GetScopesResponse, GetServiceTokensParams, GetServiceTokensResponse, GetUserByTokenRequest, GetUserByTokenResponse, GetUserRolesAndGrantsParams, GetUsersParams, GetUsersResponse, IntrospectAccessiTokenRequest, IntrospectAccessiTokenResponse, LoginAsRequest, LoginAsResponse, LoginRequest, LoginResponse, PublicRegisterRequest, RefreshTokenRequest, RefreshTokenResponse, RegisterRequest, RegisterResponse, ResendTwoFactorRequest, Role, SendResetPasswordEmailRequest, ServeResetPasswordPageParams, SetMenuScopesRequest, SetPasswordLoginPolicyRequest, SetScopeMenusRequest, SetStatoRegistrazioneDto, SetUserPasswordRequest, UpdateEnabledStatusRequest, UpdateFederatedIdentityRequest, UpdateFederatedProviderRequest, UpdateFilterTypeRequest, UpdateMenuGroupRequest, UpdateMenuRequest, UpdateMenuTypeRequest, UpdateScopeRequest, UserDto, UserGrantsResponse, VerifyTwoFactorRequest } from './model';
|
|
7
|
+
import type { ActionResponse, AdminBootstrapStatusResponse, AssignPermissionsToUserRequest, AssignRolesToUserRequest, BootstrapAdminRequest, BootstrapAdminResponse, ConfirmResetPasswordRequest, ConsoleEntryExchangeRequest, ConsoleEntrySessionResponse, ConsoleEntryTicketResponse, CreateFederatedIdentityRequest, CreateFederatedProviderRequest, CreateFederatedUserRequest, CreateFilterTypeRequest, CreateMenuGroupRequest, CreateMenuRequest, CreateMenuTypeRequest, CreateScopeRequest, CreateServiceTokenRequest, CreateServiceTokenResponse, ErrorResponse, ExchangeFederatedIdentityRequest, FederatedExchangeResponse, FederatedIdentityListResponse, FederatedIdentityResponse, FederatedProviderListResponse, FederatedProviderResponse, FiltriUtente, GetFiltriResponse, GetFiltriUtenteParams, GetFiltriUtenteResponse, GetGroupsWithMenusParams, GetGroupsWithMenusResponse, GetMenuScopesResponse, GetMenuTypesResponse, GetMenusParams, GetMenusResponse, GetRolesResponse, GetSchemaResponse, GetScopesResponse, GetServiceTokensParams, GetServiceTokensResponse, GetUserByTokenRequest, GetUserByTokenResponse, GetUserRolesAndGrantsParams, GetUsersParams, GetUsersResponse, IntrospectAccessiTokenRequest, IntrospectAccessiTokenResponse, LoginAsRequest, LoginAsResponse, LoginRequest, LoginResponse, PublicRegisterRequest, RefreshTokenRequest, RefreshTokenResponse, RegisterRequest, RegisterResponse, ResendTwoFactorRequest, RevokeTokenRequest, Role, SendResetPasswordEmailRequest, ServeResetPasswordPageParams, SetMenuScopesRequest, SetPasswordLoginPolicyRequest, SetScopeMenusRequest, SetStatoRegistrazioneDto, SetUserPasswordRequest, UpdateEnabledStatusRequest, UpdateFederatedIdentityRequest, UpdateFederatedProviderRequest, UpdateFilterTypeRequest, UpdateMenuGroupRequest, UpdateMenuRequest, UpdateMenuTypeRequest, UpdateScopeRequest, UserDto, UserGrantsResponse, VerifyTwoFactorRequest } from './model';
|
|
8
8
|
/**
|
|
9
9
|
* @summary Serve una pagina per il reset della password
|
|
10
10
|
*/
|
|
@@ -51,6 +51,16 @@ export type revokeSessionsResponse = {
|
|
|
51
51
|
};
|
|
52
52
|
export declare const getRevokeSessionsUrl: () => string;
|
|
53
53
|
export declare const revokeSessions: (options?: RequestInit) => Promise<revokeSessionsResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Annulla un solo token (logout del dispositivo corrente o token compromesso) senza toccare le altre sessioni. Se il body non contiene jti viene revocato il token della richiesta. Richiede accessTokenRevocation.store configurato.
|
|
56
|
+
* @summary Revoca un singolo access token tramite jti
|
|
57
|
+
*/
|
|
58
|
+
export type revokeTokenResponse = {
|
|
59
|
+
data: ActionResponse;
|
|
60
|
+
status: number;
|
|
61
|
+
};
|
|
62
|
+
export declare const getRevokeTokenUrl: () => string;
|
|
63
|
+
export declare const revokeToken: (revokeTokenRequest: RevokeTokenRequest, options?: RequestInit) => Promise<revokeTokenResponse>;
|
|
54
64
|
/**
|
|
55
65
|
* Con sola email restituisce passwordRequired oppure avvia il codice per utenti passwordless. Con password valida restituisce il login completo o challenge se la 2FA e attiva. Nessun JWT viene emesso prima della verifica del codice.
|
|
56
66
|
* @summary Effettua il login utente
|
|
@@ -9,10 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.introspectAccessiToken = exports.getIntrospectAccessiTokenUrl = exports.getSchema = exports.getGetSchemaUrl = exports.rotateServiceToken = exports.getRotateServiceTokenUrl = void 0;
|
|
12
|
+
exports.deleteMenu = exports.getDeleteMenuUrl = exports.updateMenu = exports.getUpdateMenuUrl = exports.createMenuType = exports.getCreateMenuTypeUrl = exports.getMenuTypes = exports.getGetMenuTypesUrl = exports.getGroupsWithMenus = exports.getGetGroupsWithMenusUrl = exports.createMenu = exports.getCreateMenuUrl = exports.getMenus = exports.getGetMenusUrl = exports.deleteRole = exports.getDeleteRoleUrl = exports.assignPermissionsToUser = exports.getAssignPermissionsToUserUrl = exports.assignRolesToUser = exports.getAssignRolesToUserUrl = exports.createRole = exports.getCreateRoleUrl = exports.updateRole = exports.getUpdateRoleUrl = exports.getRoles = exports.getGetRolesUrl = exports.getAdminBootstrapStatus = exports.getGetAdminBootstrapStatusUrl = exports.bootstrapAdmin = exports.getBootstrapAdminUrl = exports.resendTwoFactor = exports.getResendTwoFactorUrl = exports.verifyTwoFactor = exports.getVerifyTwoFactorUrl = exports.refreshAccessToken = exports.getRefreshAccessTokenUrl = exports.login = exports.getLoginUrl = exports.revokeToken = exports.getRevokeTokenUrl = exports.revokeSessions = exports.getRevokeSessionsUrl = exports.getUserByToken = exports.getGetUserByTokenUrl = exports.resetPassword = exports.getResetPasswordUrl = exports.sendPasswordResetEmail = exports.getSendPasswordResetEmailUrl = exports.serveResetPasswordPage = exports.getServeResetPasswordPageUrl = void 0;
|
|
13
|
+
exports.updateUtente = exports.getUpdateUtenteUrl = exports.createManagedUser = exports.getCreateManagedUserUrl = exports.register = exports.getRegisterUrl = exports.setStatoRegistrazione = exports.getSetStatoRegistrazioneUrl = exports.setUserPassword = exports.getSetUserPasswordUrl = exports.createLoginAsUrl = exports.getCreateLoginAsUrlUrl = exports.forcePasswordResetLegacy = exports.getForcePasswordResetLegacyUrl = exports.forcePasswordReset = exports.getForcePasswordResetUrl = exports.deleteUserPermanently = exports.getDeleteUserPermanentlyUrl = exports.deleteUser = exports.getDeleteUserUrl = exports.getUsers = exports.getGetUsersUrl = exports.serveResetPasswordPageUser = exports.getServeResetPasswordPageUserUrl = exports.setScopeMenus = exports.getSetScopeMenusUrl = exports.setMenuScopes = exports.getSetMenuScopesUrl = exports.getMenuScopes = exports.getGetMenuScopesUrl = exports.deleteScope = exports.getDeleteScopeUrl = exports.updateScope = exports.getUpdateScopeUrl = exports.createScope = exports.getCreateScopeUrl = exports.getScopes = exports.getGetScopesUrl = exports.getUserRolesAndGrants = exports.getGetUserRolesAndGrantsUrl = exports.deleteMenuType = exports.getDeleteMenuTypeUrl = exports.updateMenuType = exports.getUpdateMenuTypeUrl = exports.deleteMenuGroup = exports.getDeleteMenuGroupUrl = exports.updateMenuGroup = exports.getUpdateMenuGroupUrl = exports.createMenuGroup = exports.getCreateMenuGroupUrl = void 0;
|
|
14
|
+
exports.getServiceTokens = exports.getGetServiceTokensUrl = exports.createServiceToken = exports.getCreateServiceTokenUrl = exports.exchangeFederatedIdentity = exports.getExchangeFederatedIdentityUrl = exports.exchangeConsoleEntryTicket = exports.getExchangeConsoleEntryTicketUrl = exports.createConsoleEntryTicket = exports.getCreateConsoleEntryTicketUrl = exports.deleteFederatedIdentityPermanently = exports.getDeleteFederatedIdentityPermanentlyUrl = exports.updateFederatedIdentity = exports.getUpdateFederatedIdentityUrl = exports.disableFederatedIdentity = exports.getDisableFederatedIdentityUrl = exports.setPasswordLoginPolicy = exports.getSetPasswordLoginPolicyUrl = exports.createFederatedUser = exports.getCreateFederatedUserUrl = exports.linkFederatedIdentity = exports.getLinkFederatedIdentityUrl = exports.getFederatedIdentities = exports.getGetFederatedIdentitiesUrl = exports.deleteFederatedProvider = exports.getDeleteFederatedProviderUrl = exports.updateFederatedProvider = exports.getUpdateFederatedProviderUrl = exports.createFederatedProvider = exports.getCreateFederatedProviderUrl = exports.getFederatedProviders = exports.getGetFederatedProvidersUrl = exports.setGroupEnabled = exports.getSetGroupEnabledUrl = exports.setMenuEnabled = exports.getSetMenuEnabledUrl = exports.saveFiltriUtente = exports.getSaveFiltriUtenteUrl = exports.getFiltriUtente = exports.getGetFiltriUtenteUrl = exports.deleteTipoFiltro = exports.getDeleteTipoFiltroUrl = exports.updateTipoFiltro = exports.getUpdateTipoFiltroUrl = exports.createTipoFiltro = exports.getCreateTipoFiltroUrl = exports.getTipiFiltro = exports.getGetTipiFiltroUrl = exports.setGdpr = exports.getSetGdprUrl = void 0;
|
|
15
|
+
exports.introspectAccessiToken = exports.getIntrospectAccessiTokenUrl = exports.getSchema = exports.getGetSchemaUrl = exports.rotateServiceToken = exports.getRotateServiceTokenUrl = exports.revokeServiceToken = exports.getRevokeServiceTokenUrl = void 0;
|
|
16
16
|
const accessiFetch_1 = require("../accessiFetch");
|
|
17
17
|
const getServeResetPasswordPageUrl = (token, params) => {
|
|
18
18
|
const normalizedParams = new URLSearchParams();
|
|
@@ -63,6 +63,14 @@ const revokeSessions = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
63
63
|
return (0, accessiFetch_1.accessiFetch)((0, exports.getRevokeSessionsUrl)(), Object.assign(Object.assign({}, options), { method: 'POST' }));
|
|
64
64
|
});
|
|
65
65
|
exports.revokeSessions = revokeSessions;
|
|
66
|
+
const getRevokeTokenUrl = () => {
|
|
67
|
+
return `/api/accessi/auth/revoke-token`;
|
|
68
|
+
};
|
|
69
|
+
exports.getRevokeTokenUrl = getRevokeTokenUrl;
|
|
70
|
+
const revokeToken = (revokeTokenRequest, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
71
|
+
return (0, accessiFetch_1.accessiFetch)((0, exports.getRevokeTokenUrl)(), Object.assign(Object.assign({}, options), { method: 'POST', body: JSON.stringify(revokeTokenRequest) }));
|
|
72
|
+
});
|
|
73
|
+
exports.revokeToken = revokeToken;
|
|
66
74
|
const getLoginUrl = () => {
|
|
67
75
|
return `/api/accessi/auth/login`;
|
|
68
76
|
};
|