emilsoftware-utilities 2.0.0-dev.78 → 2.0.0-dev.79
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/client/generated/admin.d.ts +21 -1
- package/dist/accessi/client/generated/admin.js +35 -1
- package/dist/accessi/client/generated/admin.js.map +1 -1
- package/dist/accessi-module/AccessiModule.d.ts +3 -0
- package/dist/accessi-module/AccessiModule.js +4 -0
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.js +1 -0
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.d.ts +21 -1
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js +35 -1
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/exportAuditOrder.d.ts +11 -0
- package/dist/accessi-module/Console/generated/model/exportAuditOrder.js +15 -0
- package/dist/accessi-module/Console/generated/model/exportAuditOrder.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/exportAuditParams.d.ts +37 -0
- package/dist/accessi-module/Console/generated/model/exportAuditParams.js +3 -0
- package/dist/accessi-module/Console/generated/model/exportAuditParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +4 -0
- package/dist/accessi-module/Console/generated/model/index.js +4 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/queryAuditOrder.d.ts +11 -0
- package/dist/accessi-module/Console/generated/model/queryAuditOrder.js +15 -0
- package/dist/accessi-module/Console/generated/model/queryAuditOrder.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/queryAuditParams.d.ts +37 -0
- package/dist/accessi-module/Console/generated/model/queryAuditParams.js +3 -0
- package/dist/accessi-module/Console/generated/model/queryAuditParams.js.map +1 -0
- package/dist/accessi-module/Console/wiki.js +1 -0
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiAuditController.d.ts +16 -0
- package/dist/accessi-module/Controllers/AccessiAuditController.js +155 -0
- package/dist/accessi-module/Controllers/AccessiAuditController.js.map +1 -0
- package/dist/accessi-module/Controllers/AuthController.js +15 -0
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Controllers/ConsoleEntryController.js +6 -0
- package/dist/accessi-module/Controllers/ConsoleEntryController.js.map +1 -1
- package/dist/accessi-module/Dtos/AuditDtos.d.ts +10 -0
- package/dist/accessi-module/Dtos/AuditDtos.js +68 -0
- package/dist/accessi-module/Dtos/AuditDtos.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/index.d.ts +5 -1
- package/dist/accessi-module/index.js +14 -3
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/security/audit.d.ts +68 -3
- package/dist/accessi-module/security/audit.js +177 -4
- package/dist/accessi-module/security/audit.js.map +1 -1
- package/dist/accessi-module/security/auditSinks.d.ts +55 -0
- package/dist/accessi-module/security/auditSinks.js +228 -0
- package/dist/accessi-module/security/auditSinks.js.map +1 -0
- package/dist/accessi-module/security/jwtTokenOptions.js +2 -0
- package/dist/accessi-module/security/jwtTokenOptions.js.map +1 -1
- package/dist/accessi-module/security/publicAuthRateLimit.js +7 -0
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/security/sessionRevocation.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.79.tgz +0 -0
- package/docs/audit.md +136 -0
- package/package.json +3 -3
- package/dist/emilsoftware-utilities-2.0.0-dev.78.tgz +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
var AccessiAuditController_1;
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.AccessiAuditController = void 0;
|
|
26
|
+
const common_1 = require("@nestjs/common");
|
|
27
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
28
|
+
const Utilities_1 = require("../../Utilities");
|
|
29
|
+
const Dtos_1 = require("../Dtos");
|
|
30
|
+
const jwt_strategy_1 = require("../jwt/jwt.strategy");
|
|
31
|
+
const accessControl_1 = require("../security/accessControl");
|
|
32
|
+
const audit_1 = require("../security/audit");
|
|
33
|
+
/** Dimensione massima della pagina usata dall'export NDJSON. */
|
|
34
|
+
const EXPORT_PAGE_SIZE = 1000;
|
|
35
|
+
/** Limite di sicurezza per un singolo export. */
|
|
36
|
+
const EXPORT_MAX_RECORDS = 100000;
|
|
37
|
+
/**
|
|
38
|
+
* Consultazione ed export dell'audit persistente.
|
|
39
|
+
*
|
|
40
|
+
* Richiede un utente super/admin Accessi. Se non e configurato uno store
|
|
41
|
+
* interrogabile (`audit.store` o un sink con `query`), risponde 501 con un
|
|
42
|
+
* codice stabile: l'host puo continuare a usare il solo log strutturato.
|
|
43
|
+
*/
|
|
44
|
+
let AccessiAuditController = AccessiAuditController_1 = class AccessiAuditController {
|
|
45
|
+
store() {
|
|
46
|
+
const store = (0, audit_1.getAccessiAuditStore)();
|
|
47
|
+
if (!store) {
|
|
48
|
+
throw new common_1.HttpException({
|
|
49
|
+
code: 'ACCESSI_AUDIT_STORE_DISABLED',
|
|
50
|
+
message: 'Audit persistente non configurato su questa istanza.',
|
|
51
|
+
}, common_1.HttpStatus.NOT_IMPLEMENTED);
|
|
52
|
+
}
|
|
53
|
+
return store;
|
|
54
|
+
}
|
|
55
|
+
static toQuery(request) {
|
|
56
|
+
var _a;
|
|
57
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (((_a = request.event) === null || _a === void 0 ? void 0 : _a.trim()) ? { event: request.event.trim() } : {})), (request.from ? { from: request.from } : {})), (request.to ? { to: request.to } : {})), (request.codiceUtente !== undefined ? { codiceUtente: request.codiceUtente } : {})), (request.limit !== undefined ? { limit: request.limit } : {})), (request.offset !== undefined ? { offset: request.offset } : {})), (request.order ? { order: request.order } : {}));
|
|
58
|
+
}
|
|
59
|
+
authorize(request) {
|
|
60
|
+
const user = (0, accessControl_1.getAuthenticatedAccessiUser)(request);
|
|
61
|
+
(0, accessControl_1.ensureConsoleAccess)(user, 'La consultazione audit richiede un superutente o un admin Accessi.');
|
|
62
|
+
}
|
|
63
|
+
query(request, query, res) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
try {
|
|
66
|
+
this.authorize(request);
|
|
67
|
+
const page = yield this.store().query(AccessiAuditController_1.toQuery(query));
|
|
68
|
+
return Utilities_1.RestUtilities.sendBaseResponse(res, page);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return Utilities_1.RestUtilities.sendErrorMessage(res, error, AccessiAuditController_1.name, error instanceof common_1.HttpException ? error.getStatus() : common_1.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export(request, query, res) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
try {
|
|
78
|
+
this.authorize(request);
|
|
79
|
+
const store = this.store();
|
|
80
|
+
const filter = AccessiAuditController_1.toQuery(Object.assign(Object.assign({}, query), { limit: undefined, offset: undefined }));
|
|
81
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
82
|
+
res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8');
|
|
83
|
+
res.setHeader('Cache-Control', 'no-store, max-age=0');
|
|
84
|
+
res.setHeader('Content-Disposition', `attachment; filename="accessi-audit-${date}.ndjson"`);
|
|
85
|
+
let offset = 0;
|
|
86
|
+
let written = 0;
|
|
87
|
+
for (;;) {
|
|
88
|
+
const remaining = EXPORT_MAX_RECORDS - written;
|
|
89
|
+
if (remaining <= 0)
|
|
90
|
+
break;
|
|
91
|
+
const page = yield store.query(Object.assign(Object.assign({}, filter), { limit: Math.min(EXPORT_PAGE_SIZE, remaining), offset }));
|
|
92
|
+
for (const record of page.records) {
|
|
93
|
+
res.write(`${JSON.stringify(record)}\n`);
|
|
94
|
+
written += 1;
|
|
95
|
+
}
|
|
96
|
+
offset += page.records.length;
|
|
97
|
+
if (page.records.length === 0 || offset >= page.total)
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
res.end();
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (res.headersSent) {
|
|
105
|
+
// L'export e gia iniziato: chiudere in modo esplicito invece di inviare JSON sopra l'NDJSON.
|
|
106
|
+
res.end();
|
|
107
|
+
return res;
|
|
108
|
+
}
|
|
109
|
+
return Utilities_1.RestUtilities.sendErrorMessage(res, error, AccessiAuditController_1.name, error instanceof common_1.HttpException ? error.getStatus() : common_1.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
exports.AccessiAuditController = AccessiAuditController;
|
|
115
|
+
__decorate([
|
|
116
|
+
(0, common_1.Get)(),
|
|
117
|
+
(0, swagger_1.ApiOperation)({
|
|
118
|
+
operationId: 'queryAudit',
|
|
119
|
+
summary: 'Elenca gli eventi di audit persistiti',
|
|
120
|
+
description: 'Richiede audit.store o un sink interrogabile. Supporta filtro per evento, intervallo, utente e paginazione.',
|
|
121
|
+
}),
|
|
122
|
+
(0, swagger_1.ApiOkResponse)({ description: 'Pagina di record di audit redatti.' }),
|
|
123
|
+
(0, swagger_1.ApiResponse)({ status: 401, type: Dtos_1.ErrorResponse, description: 'Token Accessi mancante o non valido.' }),
|
|
124
|
+
(0, swagger_1.ApiResponse)({ status: 403, type: Dtos_1.ErrorResponse, description: 'Utente non abilitato alla console.' }),
|
|
125
|
+
(0, swagger_1.ApiResponse)({ status: 501, type: Dtos_1.ErrorResponse, description: 'Audit persistente non configurato.' }),
|
|
126
|
+
__param(0, (0, common_1.Req)()),
|
|
127
|
+
__param(1, (0, common_1.Query)()),
|
|
128
|
+
__param(2, (0, common_1.Res)()),
|
|
129
|
+
__metadata("design:type", Function),
|
|
130
|
+
__metadata("design:paramtypes", [Object, Dtos_1.AuditQueryRequest, Object]),
|
|
131
|
+
__metadata("design:returntype", Promise)
|
|
132
|
+
], AccessiAuditController.prototype, "query", null);
|
|
133
|
+
__decorate([
|
|
134
|
+
(0, common_1.Get)('export'),
|
|
135
|
+
(0, swagger_1.ApiOperation)({
|
|
136
|
+
operationId: 'exportAudit',
|
|
137
|
+
summary: 'Esporta gli eventi di audit in NDJSON',
|
|
138
|
+
description: 'Stessi filtri della query, senza paginazione. Il file contiene record gia redatti; limite di sicurezza 100000 record.',
|
|
139
|
+
}),
|
|
140
|
+
(0, swagger_1.ApiResponse)({ status: 200, description: 'NDJSON scaricabile.' }),
|
|
141
|
+
(0, swagger_1.ApiResponse)({ status: 501, type: Dtos_1.ErrorResponse, description: 'Audit persistente non configurato.' }),
|
|
142
|
+
__param(0, (0, common_1.Req)()),
|
|
143
|
+
__param(1, (0, common_1.Query)()),
|
|
144
|
+
__param(2, (0, common_1.Res)()),
|
|
145
|
+
__metadata("design:type", Function),
|
|
146
|
+
__metadata("design:paramtypes", [Object, Dtos_1.AuditQueryRequest, Object]),
|
|
147
|
+
__metadata("design:returntype", Promise)
|
|
148
|
+
], AccessiAuditController.prototype, "export", null);
|
|
149
|
+
exports.AccessiAuditController = AccessiAuditController = AccessiAuditController_1 = __decorate([
|
|
150
|
+
(0, swagger_1.ApiTags)('Audit'),
|
|
151
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
152
|
+
(0, common_1.Controller)('accessi/audit'),
|
|
153
|
+
(0, common_1.UseGuards)(jwt_strategy_1.JwtSimpleGuard)
|
|
154
|
+
], AccessiAuditController);
|
|
155
|
+
//# sourceMappingURL=AccessiAuditController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccessiAuditController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/AccessiAuditController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Controller,\n Get,\n HttpException,\n HttpStatus,\n Query,\n Req,\n Res,\n UseGuards,\n} from '@nestjs/common';\nimport {\n ApiBearerAuth,\n ApiOkResponse,\n ApiOperation,\n ApiResponse,\n ApiTags,\n} from '@nestjs/swagger';\nimport { Request, Response } from 'express';\nimport { RestUtilities } from '../../Utilities';\nimport { AuditQueryRequest, ErrorResponse } from '../Dtos';\nimport { JwtSimpleGuard } from '../jwt/jwt.strategy';\nimport { ensureConsoleAccess, getAuthenticatedAccessiUser } from '../security/accessControl';\nimport { getAccessiAuditStore } from '../security/audit';\nimport type { AccessiAuditQuery, AccessiAuditQueryableSink } from '../security/audit';\n\n/** Dimensione massima della pagina usata dall'export NDJSON. */\nconst EXPORT_PAGE_SIZE = 1_000;\n/** Limite di sicurezza per un singolo export. */\nconst EXPORT_MAX_RECORDS = 100_000;\n\n/**\n * Consultazione ed export dell'audit persistente.\n *\n * Richiede un utente super/admin Accessi. Se non e configurato uno store\n * interrogabile (`audit.store` o un sink con `query`), risponde 501 con un\n * codice stabile: l'host puo continuare a usare il solo log strutturato.\n */\n@ApiTags('Audit')\n@ApiBearerAuth()\n@Controller('accessi/audit')\n@UseGuards(JwtSimpleGuard)\nexport class AccessiAuditController {\n private store(): AccessiAuditQueryableSink {\n const store = getAccessiAuditStore();\n if (!store) {\n throw new HttpException(\n {\n code: 'ACCESSI_AUDIT_STORE_DISABLED',\n message: 'Audit persistente non configurato su questa istanza.',\n },\n HttpStatus.NOT_IMPLEMENTED,\n );\n }\n return store;\n }\n\n private static toQuery(request: AuditQueryRequest): AccessiAuditQuery {\n return {\n ...(request.event?.trim() ? { event: request.event.trim() } : {}),\n ...(request.from ? { from: request.from } : {}),\n ...(request.to ? { to: request.to } : {}),\n ...(request.codiceUtente !== undefined ? { codiceUtente: request.codiceUtente } : {}),\n ...(request.limit !== undefined ? { limit: request.limit } : {}),\n ...(request.offset !== undefined ? { offset: request.offset } : {}),\n ...(request.order ? { order: request.order } : {}),\n };\n }\n\n private authorize(request: Request): void {\n const user = getAuthenticatedAccessiUser(request);\n ensureConsoleAccess(user, 'La consultazione audit richiede un superutente o un admin Accessi.');\n }\n\n @Get()\n @ApiOperation({\n operationId: 'queryAudit',\n summary: 'Elenca gli eventi di audit persistiti',\n description:\n 'Richiede audit.store o un sink interrogabile. Supporta filtro per evento, intervallo, utente e paginazione.',\n })\n @ApiOkResponse({ description: 'Pagina di record di audit redatti.' })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Utente non abilitato alla console.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Audit persistente non configurato.' })\n async query(\n @Req() request: Request,\n @Query() query: AuditQueryRequest,\n @Res() res: Response,\n ): Promise<Response> {\n try {\n this.authorize(request);\n const page = await this.store().query(AccessiAuditController.toQuery(query));\n return RestUtilities.sendBaseResponse(res, page);\n } catch (error) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AccessiAuditController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Get('export')\n @ApiOperation({\n operationId: 'exportAudit',\n summary: 'Esporta gli eventi di audit in NDJSON',\n description:\n 'Stessi filtri della query, senza paginazione. Il file contiene record gia redatti; limite di sicurezza 100000 record.',\n })\n @ApiResponse({ status: 200, description: 'NDJSON scaricabile.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Audit persistente non configurato.' })\n async export(\n @Req() request: Request,\n @Query() query: AuditQueryRequest,\n @Res() res: Response,\n ): Promise<Response | void> {\n try {\n this.authorize(request);\n const store = this.store();\n const filter = AccessiAuditController.toQuery({ ...query, limit: undefined, offset: undefined });\n const date = new Date().toISOString().slice(0, 10);\n res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store, max-age=0');\n res.setHeader('Content-Disposition', `attachment; filename=\"accessi-audit-${date}.ndjson\"`);\n\n let offset = 0;\n let written = 0;\n for (;;) {\n const remaining = EXPORT_MAX_RECORDS - written;\n if (remaining <= 0) break;\n const page = await store.query({\n ...filter,\n limit: Math.min(EXPORT_PAGE_SIZE, remaining),\n offset,\n });\n for (const record of page.records) {\n res.write(`${JSON.stringify(record)}\\n`);\n written += 1;\n }\n offset += page.records.length;\n if (page.records.length === 0 || offset >= page.total) break;\n }\n res.end();\n return res;\n } catch (error) {\n if (res.headersSent) {\n // L'export e gia iniziato: chiudere in modo esplicito invece di inviare JSON sopra l'NDJSON.\n res.end();\n return res;\n }\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AccessiAuditController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n}\n"]}
|
|
@@ -171,6 +171,7 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
171
171
|
}
|
|
172
172
|
login(request, loginRequest, res) {
|
|
173
173
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
var _a;
|
|
174
175
|
const startedAt = Date.now();
|
|
175
176
|
try {
|
|
176
177
|
const rateLimitDecision = yield (0, publicAuthRateLimit_1.checkPublicAuthRateLimit)(this.options, 'login', request, [loginRequest === null || loginRequest === void 0 ? void 0 : loginRequest.email]);
|
|
@@ -181,6 +182,7 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
181
182
|
const userData = yield this.authService.login(loginRequest);
|
|
182
183
|
if (!userData) {
|
|
183
184
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_login_total', { result: 'failure' });
|
|
185
|
+
(0, audit_1.auditAccessi)('login_failed', { result: 'failure', ip: request.ip, emailProvided: Boolean(loginRequest === null || loginRequest === void 0 ? void 0 : loginRequest.email) });
|
|
184
186
|
return Utilities_1.RestUtilities.sendInvalidCredentials(res);
|
|
185
187
|
}
|
|
186
188
|
if (!userData.challenge && !userData.passwordRequired) {
|
|
@@ -196,6 +198,12 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
196
198
|
? 'password_required'
|
|
197
199
|
: 'success';
|
|
198
200
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_login_total', { result });
|
|
201
|
+
if (result === 'success') {
|
|
202
|
+
(0, audit_1.auditAccessi)('login_succeeded', {
|
|
203
|
+
codiceUtente: (_a = userData.utente) === null || _a === void 0 ? void 0 : _a.codiceUtente,
|
|
204
|
+
ip: request.ip,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
199
207
|
return Utilities_1.RestUtilities.sendBaseResponse(res, userData);
|
|
200
208
|
}
|
|
201
209
|
catch (error) {
|
|
@@ -206,6 +214,7 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
206
214
|
? 'sso_only'
|
|
207
215
|
: 'error';
|
|
208
216
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_login_total', { result });
|
|
217
|
+
(0, audit_1.auditAccessi)('login_failed', { result, ip: request.ip, emailProvided: Boolean(loginRequest === null || loginRequest === void 0 ? void 0 : loginRequest.email) });
|
|
209
218
|
if (message === 'PASSWORD_EXPIRED') {
|
|
210
219
|
this.logger.warning('Password scaduta, cambiare password ', error);
|
|
211
220
|
return Utilities_1.RestUtilities.sendPasswordExpired(res);
|
|
@@ -261,6 +270,7 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
261
270
|
const response = Object.assign({ token: result.token }, (result.refreshToken ? { refreshToken: result.refreshToken } : {}));
|
|
262
271
|
(0, authCookies_1.applyAccessiAuthCookies)(res, cookieConfig, response);
|
|
263
272
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_refresh_total', { result: 'success' });
|
|
273
|
+
(0, audit_1.auditAccessi)('refresh_succeeded', { ip: request.ip });
|
|
264
274
|
return Utilities_1.RestUtilities.sendBaseResponse(res, response);
|
|
265
275
|
}
|
|
266
276
|
catch (error) {
|
|
@@ -273,6 +283,8 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
273
283
|
? 'store_unavailable'
|
|
274
284
|
: 'invalid';
|
|
275
285
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_refresh_total', { result });
|
|
286
|
+
if (result !== 'reuse')
|
|
287
|
+
(0, audit_1.auditAccessi)('refresh_failed', { result, ip: request.ip });
|
|
276
288
|
return Utilities_1.RestUtilities.sendErrorMessage(res, error, AuthController_1.name, error instanceof common_1.HttpException ? error.getStatus() : common_1.HttpStatus.UNAUTHORIZED);
|
|
277
289
|
}
|
|
278
290
|
finally {
|
|
@@ -282,6 +294,7 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
282
294
|
}
|
|
283
295
|
verifyTwoFactor(request, body, res) {
|
|
284
296
|
return __awaiter(this, void 0, void 0, function* () {
|
|
297
|
+
var _a;
|
|
285
298
|
const startedAt = Date.now();
|
|
286
299
|
try {
|
|
287
300
|
const limit = yield (0, publicAuthRateLimit_1.checkPublicAuthRateLimit)(this.options, 'twoFactorVerify', request, [body.challengeId]);
|
|
@@ -292,10 +305,12 @@ let AuthController = AuthController_1 = class AuthController {
|
|
|
292
305
|
const result = yield this.authService.verifyTwoFactor(body.challengeId, body.code, body.scope);
|
|
293
306
|
(0, authCookies_1.applyAccessiAuthCookies)(res, (0, authCookies_1.resolveAccessiAuthCookieOptions)(this.options), result);
|
|
294
307
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_two_factor_total', { action: 'verify', result: 'success' });
|
|
308
|
+
(0, audit_1.auditAccessi)('two_factor_succeeded', { codiceUtente: (_a = result.utente) === null || _a === void 0 ? void 0 : _a.codiceUtente, ip: request.ip });
|
|
295
309
|
return Utilities_1.RestUtilities.sendBaseResponse(res, result);
|
|
296
310
|
}
|
|
297
311
|
catch (error) {
|
|
298
312
|
(0, metrics_1.countAccessiMetric)(this.options, 'auth_two_factor_total', { action: 'verify', result: 'failure' });
|
|
313
|
+
(0, audit_1.auditAccessi)('two_factor_failed', { ip: request.ip });
|
|
299
314
|
return Utilities_1.RestUtilities.sendErrorMessage(res, error, AuthController_1.name, error instanceof common_1.HttpException ? error.getStatus() : 500);
|
|
300
315
|
}
|
|
301
316
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/AuthController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Get, HttpException, HttpStatus, Inject, Param, Post, Req, Res, UseGuards } from '@nestjs/common';\nimport { ResendTwoFactorRequest, VerifyTwoFactorRequest } from '../Dtos/TwoFactorDtos';\nimport { ApiBody, ApiOkResponse, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';\nimport { Request, Response } from 'express';\nimport { createHash } from 'crypto';\nimport { Logger } from '../../Logger';\nimport { RestUtilities } from '../../Utilities';\nimport type { AccessiOptions } from '../AccessiModule';\nimport {\n ActionResponse,\n AdminBootstrapStatusResponse,\n BootstrapAdminRequest,\n BootstrapAdminResponse,\n ConfirmResetPasswordRequest,\n ErrorResponse,\n GetUserByTokenRequest,\n GetUserByTokenResponse,\n LoginRequest,\n LoginResponse,\n PasswordExpiredResponse,\n RefreshTokenRequest,\n RefreshTokenResponse,\n RevokeTokenRequest,\n} from '../Dtos';\nimport { AuthService, PASSWORD_LOGIN_DISABLED } from '../Services/AuthService/AuthService';\nimport { AdminBootstrapService } from '../Services/AdminBootstrapService/AdminBootstrapService';\nimport { JwtSimpleGuard } from '../jwt/jwt.strategy';\nimport { getAuthenticatedAccessiUser } from '../security/accessControl';\nimport { extractAccessiBearerToken } from '../security/authenticatedToken';\nimport {\n applyAccessiAuthCookies,\n clearAccessiAuthCookies,\n getAccessiRefreshTokenFromCookie,\n resolveAccessiAuthCookieOptions,\n} from '../security/authCookies';\nimport {\n countAccessiMetric,\n observeAccessiMetric,\n} from '../observability/metrics';\nimport {\n getSessionRevocationStore,\n revokeAccessiUserSessions,\n} from '../security/sessionRevocation';\nimport {\n getAccessTokenRevocationStore,\n revokeAccessiAccessToken,\n} from '../security/accessTokenRevocation';\nimport { auditAccessi } from '../security/audit';\nimport {\n checkPublicAuthRateLimit,\n sendPublicAuthRateLimitExceeded,\n} from '../security/publicAuthRateLimit';\n\n/** Estrae il codice stabile di un errore Nest `{ code, message }`. */\nfunction authErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== 'object') return undefined;\n const response = typeof (error as { getResponse?: unknown }).getResponse === 'function'\n ? (error as { getResponse: () => unknown }).getResponse()\n : (error as { response?: unknown }).response;\n if (response && typeof response === 'object') {\n const code = (response as { code?: unknown }).code;\n return typeof code === 'string' ? code : undefined;\n }\n return undefined;\n}\n\n@ApiTags('Auth')\n@Controller('accessi/auth')/**\n * Endpoint pubblici di autenticazione locale e verifica sessione.\n * Il login SSO non riceve token esterni qui: il backend validante usa `FederatedAuthService.authenticate`.\n */\nexport class AuthController {\n logger: Logger = new Logger(AuthController.name);\n\n constructor(\n private readonly authService: AuthService,\n private readonly adminBootstrapService: AdminBootstrapService,\n @Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions,\n ) {}\n\n @ApiOperation({ summary: 'Conferma il reset della password', operationId: 'resetPassword' })\n @ApiParam({ name: 'token', description: 'Token per il reset della password', required: true })\n @ApiBody({ type: ConfirmResetPasswordRequest })\n @ApiResponse({\n status: 200,\n description: 'Password aggiornata con successo',\n type: ActionResponse,\n })\n @ApiResponse({\n status: 400,\n description: 'Errore nella richiesta o token non valido',\n type: ErrorResponse,\n })\n @Post('confirm-reset-password/:token')\n async resetPassword(\n @Req() request: Request,\n @Res() res: Response,\n @Param('token') token: string,\n @Body() body: ConfirmResetPasswordRequest,\n ) {\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'passwordResetConfirm',\n request,\n );\n if (!rateLimitDecision.allowed) {\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n await this.authService.confirmResetPassword(token, body.newPassword);\n return RestUtilities.sendOKMessage(res, 'Password aggiornata con successo!');\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, HttpStatus.BAD_REQUEST);\n }\n }\n\n @ApiOperation({\n summary: 'Recupera le informazioni utente dal token JWT',\n operationId: 'getUserByToken',\n })\n @ApiBody({ type: GetUserByTokenRequest })\n @ApiResponse({\n status: 200,\n description: 'Informazioni utente recuperate con successo',\n type: GetUserByTokenResponse,\n })\n @ApiResponse({\n status: 401,\n description: 'Token non valido o scaduto',\n type: ErrorResponse,\n })\n @Post('get-user-by-token')\n async getUserByToken(\n @Req() request: Request,\n @Body() body: GetUserByTokenRequest,\n @Res() res: Response,\n ) {\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'getUserByToken',\n request,\n );\n if (!rateLimitDecision.allowed) {\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n const requestToken = typeof body?.token === 'string' && body.token.trim() !== ''\n ? body.token\n : extractAccessiBearerToken(request.headers.authorization);\n if (!requestToken) {\n return RestUtilities.sendErrorMessage(\n res,\n 'Token non fornito',\n AuthController.name,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n const authenticatedPayload = await this.authService.getAuthenticatedTokenPayload(requestToken);\n const userData = (authenticatedPayload as { utente?: unknown })?.utente;\n if (!userData) {\n throw new Error('Il token non contiene un utente Accessi valido.');\n }\n\n // Keep the runtime response aligned with GetUserByTokenResponse and Orval:\n // Result.userData contains the authenticated user directly, not a nested JWT payload.\n return RestUtilities.sendBaseResponse(res, { userData });\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, HttpStatus.UNAUTHORIZED);\n }\n }\n\n @ApiOperation({\n summary: 'Revoca tutte le sessioni dell utente corrente',\n operationId: 'revokeSessions',\n description:\n 'Invalida i token emessi prima di questa chiamata. Richiede sessionRevocation.store configurato. I token emessi dopo la revoca restano validi.',\n })\n @ApiOkResponse({ type: ActionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Revoca sessioni non configurata.' })\n @UseGuards(JwtSimpleGuard)\n @Post('revoke-sessions')\n async revokeSessions(@Req() request: Request, @Res() res: Response) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n if (!getSessionRevocationStore(this.options)) {\n throw new HttpException(\n {\n code: 'ACCESSI_SESSION_REVOCATION_DISABLED',\n message: 'La revoca sessioni non e configurata su questa istanza.',\n },\n HttpStatus.NOT_IMPLEMENTED,\n );\n }\n await revokeAccessiUserSessions(this.options, user.codiceUtente);\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) clearAccessiAuthCookies(res, cookieConfig);\n return RestUtilities.sendOKMessage(res, 'Sessioni revocate con successo.');\n } catch (error) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.BAD_REQUEST,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Revoca un singolo access token tramite jti',\n operationId: 'revokeToken',\n description:\n 'Annulla un solo token (logout del dispositivo corrente o token compromesso) senza toccare le altre sessioni. ' +\n 'Se il body non contiene jti viene revocato il token della richiesta. Richiede accessTokenRevocation.store configurato.',\n })\n @ApiBody({ type: RevokeTokenRequest })\n @ApiOkResponse({ type: ActionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Non autorizzato a revocare il token indicato.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Revoca token non configurata.' })\n @UseGuards(JwtSimpleGuard)\n @Post('revoke-token')\n async revokeToken(\n @Req() request: Request,\n @Body() body: RevokeTokenRequest,\n @Res() res: Response,\n ) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n if (!getAccessTokenRevocationStore(this.options)) {\n throw new HttpException(\n {\n code: 'ACCESSI_ACCESS_TOKEN_REVOCATION_DISABLED',\n message: 'La revoca dei singoli token non e configurata su questa istanza.',\n },\n HttpStatus.NOT_IMPLEMENTED,\n );\n }\n\n const payload = ((request as Request & { user?: unknown }).user ?? {}) as Record<string, unknown>;\n const currentJti = typeof payload.jti === 'string' ? payload.jti : undefined;\n const requestedJti = typeof body?.jti === 'string' ? body.jti.trim() : '';\n const targetJti = requestedJti !== '' ? requestedJti : currentJti;\n\n if (!targetJti) {\n throw new HttpException(\n { code: 'ACCESSI_TOKEN_JTI_MISSING', message: 'Il token non contiene un jti revocabile.' },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n const isCurrentToken = targetJti === currentJti;\n if (!isCurrentToken && !user.flagAdmin && !user.flagSuper) {\n throw new HttpException(\n {\n code: 'ACCESSI_TOKEN_REVOKE_FORBIDDEN',\n message: 'Solo gli amministratori possono revocare il token di un altro utente.',\n },\n HttpStatus.FORBIDDEN,\n );\n }\n\n const expiresAt = Number(payload.exp);\n await revokeAccessiAccessToken(\n this.options,\n targetJti,\n isCurrentToken && Number.isFinite(expiresAt) ? expiresAt * 1000 : undefined,\n );\n auditAccessi('access_token_revoked', {\n codiceUtente: user.codiceUtente,\n actor: user.codiceUtente,\n jti: targetJti,\n self: isCurrentToken,\n });\n if (isCurrentToken) {\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) clearAccessiAuthCookies(res, cookieConfig);\n }\n return RestUtilities.sendOKMessage(res, 'Token revocato con successo.');\n } catch (error) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.BAD_REQUEST,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Effettua il login utente',\n description:\n \"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.\",\n operationId: 'login',\n })\n @ApiBody({ type: LoginRequest })\n @ApiResponse({\n status: 200,\n description: 'Login effettuato con successo',\n type: LoginResponse,\n })\n @ApiResponse({\n status: 401,\n description: 'Credenziali non valide',\n type: ErrorResponse,\n })\n @ApiResponse({\n status: 403,\n description: 'Password scaduta, e necessario aggiornarla.',\n type: PasswordExpiredResponse,\n })\n @ApiResponse({ status: 403, description: 'Utente abilitato solo a SSO.', type: ErrorResponse })\n @Post('login')\n async login(@Req() request: Request, @Body() loginRequest: LoginRequest, @Res() res: Response) {\n const startedAt = Date.now();\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'login',\n request,\n [loginRequest?.email],\n );\n if (!rateLimitDecision.allowed) {\n countAccessiMetric(this.options, 'auth_login_total', { result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n const userData = await this.authService.login(loginRequest);\n if (!userData) {\n countAccessiMetric(this.options, 'auth_login_total', { result: 'failure' });\n return RestUtilities.sendInvalidCredentials(res);\n }\n\n if (!userData.challenge && !userData.passwordRequired) {\n const tokens = this.authService.createTokenPair(userData.utente, ['password']);\n userData.token = tokens.access;\n if (tokens.refresh) userData.refreshToken = tokens.refresh;\n applyAccessiAuthCookies(res, resolveAccessiAuthCookieOptions(this.options), userData);\n }\n\n const result = userData.challenge\n ? 'challenge'\n : userData.passwordRequired\n ? 'password_required'\n : 'success';\n countAccessiMetric(this.options, 'auth_login_total', { result });\n return RestUtilities.sendBaseResponse(res, userData);\n } catch (error) {\n const message = (error as Error)?.message;\n const result = message === 'PASSWORD_EXPIRED'\n ? 'password_expired'\n : message === PASSWORD_LOGIN_DISABLED\n ? 'sso_only'\n : 'error';\n countAccessiMetric(this.options, 'auth_login_total', { result });\n if (message === 'PASSWORD_EXPIRED') {\n this.logger.warning('Password scaduta, cambiare password ', error);\n return RestUtilities.sendPasswordExpired(res);\n }\n\n if (error instanceof HttpException) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error.getStatus());\n }\n\n if ((error as Error)?.message === PASSWORD_LOGIN_DISABLED) {\n return res.status(HttpStatus.FORBIDDEN).json({\n severity: 'error', status: HttpStatus.FORBIDDEN, statusCode: 2,\n code: PASSWORD_LOGIN_DISABLED,\n error: PASSWORD_LOGIN_DISABLED,\n message: 'Questo utente e abilitato solo tramite SSO. Accedi con un provider collegato.',\n });\n }\n\n this.logger.error('Errore durante il login', error);\n if (RestUtilities.isDatabaseSchemaError(error)) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n HttpStatus.SERVICE_UNAVAILABLE,\n );\n }\n return RestUtilities.sendInvalidCredentials(res);\n } finally {\n observeAccessiMetric(this.options, 'auth_login_duration_ms', Date.now() - startedAt);\n }\n }\n\n @ApiOperation({\n summary: 'Scambia un refresh token con un nuovo access token',\n operationId: 'refreshAccessToken',\n description:\n 'Richiede jwtOptions.refreshExpiresIn. Il refresh token ha typ=refresh e non e accettato dai guard API.',\n })\n @ApiBody({ type: RefreshTokenRequest })\n @ApiOkResponse({ type: RefreshTokenResponse })\n @ApiResponse({ status: 401, description: 'Refresh token non valido, scaduto o revocato.', type: ErrorResponse })\n @ApiResponse({ status: 429, description: 'Troppi tentativi.', type: ErrorResponse })\n @Post('refresh')\n async refresh(\n @Req() request: Request,\n @Body() body: RefreshTokenRequest,\n @Res() res: Response,\n ) {\n const startedAt = Date.now();\n try {\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n const cookieRefreshToken = cookieConfig?.refreshFromCookie\n ? getAccessiRefreshTokenFromCookie(request.headers.cookie, cookieConfig)\n : undefined;\n const refreshToken = typeof body?.refreshToken === 'string' && body.refreshToken.trim() !== ''\n ? body.refreshToken\n : cookieRefreshToken;\n const tokenKey = typeof refreshToken === 'string'\n ? createHash('sha256').update(refreshToken).digest('hex').slice(0, 32)\n : undefined;\n const decision = await checkPublicAuthRateLimit(\n this.options,\n 'refresh',\n request,\n tokenKey ? [tokenKey] : [],\n );\n if (!decision.allowed) {\n countAccessiMetric(this.options, 'auth_refresh_total', { result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, decision.retryAfterSeconds);\n }\n\n if (!refreshToken) {\n throw new HttpException('Refresh token mancante.', HttpStatus.UNAUTHORIZED);\n }\n\n const result = await this.authService.refreshAccessToken(refreshToken);\n if (!result.token) {\n throw new HttpException('Refresh token non valido.', HttpStatus.UNAUTHORIZED);\n }\n const response = {\n token: result.token,\n ...(result.refreshToken ? { refreshToken: result.refreshToken } : {}),\n };\n applyAccessiAuthCookies(res, cookieConfig, response);\n countAccessiMetric(this.options, 'auth_refresh_total', { result: 'success' });\n return RestUtilities.sendBaseResponse(res, response);\n } catch (error) {\n const code = authErrorCode(error);\n const result = code === 'ACCESSI_REFRESH_TOKEN_REUSE'\n ? 'reuse'\n : code === 'ACCESSI_REFRESH_FAMILY_REVOKED'\n ? 'family_revoked'\n : code === 'ACCESSI_REFRESH_ROTATION_UNAVAILABLE'\n ? 'store_unavailable'\n : 'invalid';\n countAccessiMetric(this.options, 'auth_refresh_total', { result });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n } finally {\n observeAccessiMetric(this.options, 'auth_refresh_duration_ms', Date.now() - startedAt);\n }\n }\n\n @Post('two-factor/verify')\n @ApiOperation({ summary: 'Verifica il codice e completa il login', operationId: 'verifyTwoFactor' })\n @ApiBody({ type: VerifyTwoFactorRequest })\n @ApiResponse({ status: 200, type: LoginResponse })\n @ApiResponse({ status: 401, type: ErrorResponse })\n @ApiResponse({ status: 429, type: ErrorResponse })\n async verifyTwoFactor(@Req() request: Request, @Body() body: VerifyTwoFactorRequest, @Res() res: Response) {\n const startedAt = Date.now();\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'twoFactorVerify', request, [body.challengeId]);\n if (!limit.allowed) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n }\n const result = await this.authService.verifyTwoFactor(body.challengeId, body.code, body.scope);\n applyAccessiAuthCookies(res, resolveAccessiAuthCookieOptions(this.options), result);\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'success' });\n return RestUtilities.sendBaseResponse(res, result);\n } catch (error) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'failure' });\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n } finally {\n observeAccessiMetric(this.options, 'auth_two_factor_duration_ms', Date.now() - startedAt, { action: 'verify' });\n }\n }\n\n @Post('two-factor/resend')\n @ApiOperation({ summary: 'Reinvia il codice, invalidando il precedente', operationId: 'resendTwoFactor' })\n @ApiBody({ type: ResendTwoFactorRequest })\n @ApiResponse({ status: 200, type: LoginResponse })\n @ApiResponse({ status: 401, type: ErrorResponse })\n @ApiResponse({ status: 429, type: ErrorResponse })\n async resendTwoFactor(@Req() request: Request, @Body() body: ResendTwoFactorRequest, @Res() res: Response) {\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'twoFactorResend', request, [body.challengeId]);\n if (!limit.allowed) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n }\n const result = await this.authService.resendTwoFactor(body.challengeId);\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'success' });\n return RestUtilities.sendBaseResponse(res, result);\n } catch (error) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'failure' });\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n }\n }\n\n @Post('bootstrap-admin')\n @ApiOperation({\n summary: 'Crea il primo utente admin (bootstrap)',\n operationId: 'bootstrapAdmin',\n description:\n 'Endpoint pubblico ma protetto dal token di avvio: attivo solo con adminBootstrap.enabled. ' +\n 'Crea un utente in stato confermato senza email, con flag admin (e super opzionale) e password fornita o generata.',\n })\n @ApiBody({ type: BootstrapAdminRequest })\n @ApiResponse({ status: 200, type: BootstrapAdminResponse })\n @ApiResponse({ status: 401, description: 'Token di bootstrap non valido', type: ErrorResponse })\n @ApiResponse({ status: 403, description: 'Bootstrap admin non abilitato', type: ErrorResponse })\n @ApiResponse({ status: 429, description: 'Troppi tentativi', type: ErrorResponse })\n async bootstrapAdmin(@Req() request: Request, @Body() body: BootstrapAdminRequest, @Res() res: Response) {\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'adminBootstrap', request);\n if (!limit.allowed) return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n return RestUtilities.sendBaseResponse(res, await this.adminBootstrapService.bootstrap(body));\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n }\n }\n\n @Get('bootstrap-admin/status')\n @ApiOperation({\n summary: 'Indica se il bootstrap admin e abilitato',\n operationId: 'getAdminBootstrapStatus',\n description:\n 'Endpoint pubblico: la console mostra la sezione \"Crea utente admin\" solo quando enabled e true.',\n })\n @ApiResponse({ status: 200, type: AdminBootstrapStatusResponse })\n async adminBootstrapStatus(@Res() res: Response) {\n return RestUtilities.sendBaseResponse(res, { enabled: this.adminBootstrapService.isEnabled() });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AuthController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/AuthController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Body, Controller, Get, HttpException, HttpStatus, Inject, Param, Post, Req, Res, UseGuards } from '@nestjs/common';\nimport { ResendTwoFactorRequest, VerifyTwoFactorRequest } from '../Dtos/TwoFactorDtos';\nimport { ApiBody, ApiOkResponse, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';\nimport { Request, Response } from 'express';\nimport { createHash } from 'crypto';\nimport { Logger } from '../../Logger';\nimport { RestUtilities } from '../../Utilities';\nimport type { AccessiOptions } from '../AccessiModule';\nimport {\n ActionResponse,\n AdminBootstrapStatusResponse,\n BootstrapAdminRequest,\n BootstrapAdminResponse,\n ConfirmResetPasswordRequest,\n ErrorResponse,\n GetUserByTokenRequest,\n GetUserByTokenResponse,\n LoginRequest,\n LoginResponse,\n PasswordExpiredResponse,\n RefreshTokenRequest,\n RefreshTokenResponse,\n RevokeTokenRequest,\n} from '../Dtos';\nimport { AuthService, PASSWORD_LOGIN_DISABLED } from '../Services/AuthService/AuthService';\nimport { AdminBootstrapService } from '../Services/AdminBootstrapService/AdminBootstrapService';\nimport { JwtSimpleGuard } from '../jwt/jwt.strategy';\nimport { getAuthenticatedAccessiUser } from '../security/accessControl';\nimport { extractAccessiBearerToken } from '../security/authenticatedToken';\nimport {\n applyAccessiAuthCookies,\n clearAccessiAuthCookies,\n getAccessiRefreshTokenFromCookie,\n resolveAccessiAuthCookieOptions,\n} from '../security/authCookies';\nimport {\n countAccessiMetric,\n observeAccessiMetric,\n} from '../observability/metrics';\nimport {\n getSessionRevocationStore,\n revokeAccessiUserSessions,\n} from '../security/sessionRevocation';\nimport {\n getAccessTokenRevocationStore,\n revokeAccessiAccessToken,\n} from '../security/accessTokenRevocation';\nimport { auditAccessi } from '../security/audit';\nimport {\n checkPublicAuthRateLimit,\n sendPublicAuthRateLimitExceeded,\n} from '../security/publicAuthRateLimit';\n\n/** Estrae il codice stabile di un errore Nest `{ code, message }`. */\nfunction authErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== 'object') return undefined;\n const response = typeof (error as { getResponse?: unknown }).getResponse === 'function'\n ? (error as { getResponse: () => unknown }).getResponse()\n : (error as { response?: unknown }).response;\n if (response && typeof response === 'object') {\n const code = (response as { code?: unknown }).code;\n return typeof code === 'string' ? code : undefined;\n }\n return undefined;\n}\n\n@ApiTags('Auth')\n@Controller('accessi/auth')/**\n * Endpoint pubblici di autenticazione locale e verifica sessione.\n * Il login SSO non riceve token esterni qui: il backend validante usa `FederatedAuthService.authenticate`.\n */\nexport class AuthController {\n logger: Logger = new Logger(AuthController.name);\n\n constructor(\n private readonly authService: AuthService,\n private readonly adminBootstrapService: AdminBootstrapService,\n @Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions,\n ) {}\n\n @ApiOperation({ summary: 'Conferma il reset della password', operationId: 'resetPassword' })\n @ApiParam({ name: 'token', description: 'Token per il reset della password', required: true })\n @ApiBody({ type: ConfirmResetPasswordRequest })\n @ApiResponse({\n status: 200,\n description: 'Password aggiornata con successo',\n type: ActionResponse,\n })\n @ApiResponse({\n status: 400,\n description: 'Errore nella richiesta o token non valido',\n type: ErrorResponse,\n })\n @Post('confirm-reset-password/:token')\n async resetPassword(\n @Req() request: Request,\n @Res() res: Response,\n @Param('token') token: string,\n @Body() body: ConfirmResetPasswordRequest,\n ) {\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'passwordResetConfirm',\n request,\n );\n if (!rateLimitDecision.allowed) {\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n await this.authService.confirmResetPassword(token, body.newPassword);\n return RestUtilities.sendOKMessage(res, 'Password aggiornata con successo!');\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, HttpStatus.BAD_REQUEST);\n }\n }\n\n @ApiOperation({\n summary: 'Recupera le informazioni utente dal token JWT',\n operationId: 'getUserByToken',\n })\n @ApiBody({ type: GetUserByTokenRequest })\n @ApiResponse({\n status: 200,\n description: 'Informazioni utente recuperate con successo',\n type: GetUserByTokenResponse,\n })\n @ApiResponse({\n status: 401,\n description: 'Token non valido o scaduto',\n type: ErrorResponse,\n })\n @Post('get-user-by-token')\n async getUserByToken(\n @Req() request: Request,\n @Body() body: GetUserByTokenRequest,\n @Res() res: Response,\n ) {\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'getUserByToken',\n request,\n );\n if (!rateLimitDecision.allowed) {\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n const requestToken = typeof body?.token === 'string' && body.token.trim() !== ''\n ? body.token\n : extractAccessiBearerToken(request.headers.authorization);\n if (!requestToken) {\n return RestUtilities.sendErrorMessage(\n res,\n 'Token non fornito',\n AuthController.name,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n const authenticatedPayload = await this.authService.getAuthenticatedTokenPayload(requestToken);\n const userData = (authenticatedPayload as { utente?: unknown })?.utente;\n if (!userData) {\n throw new Error('Il token non contiene un utente Accessi valido.');\n }\n\n // Keep the runtime response aligned with GetUserByTokenResponse and Orval:\n // Result.userData contains the authenticated user directly, not a nested JWT payload.\n return RestUtilities.sendBaseResponse(res, { userData });\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, HttpStatus.UNAUTHORIZED);\n }\n }\n\n @ApiOperation({\n summary: 'Revoca tutte le sessioni dell utente corrente',\n operationId: 'revokeSessions',\n description:\n 'Invalida i token emessi prima di questa chiamata. Richiede sessionRevocation.store configurato. I token emessi dopo la revoca restano validi.',\n })\n @ApiOkResponse({ type: ActionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Revoca sessioni non configurata.' })\n @UseGuards(JwtSimpleGuard)\n @Post('revoke-sessions')\n async revokeSessions(@Req() request: Request, @Res() res: Response) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n if (!getSessionRevocationStore(this.options)) {\n throw new HttpException(\n {\n code: 'ACCESSI_SESSION_REVOCATION_DISABLED',\n message: 'La revoca sessioni non e configurata su questa istanza.',\n },\n HttpStatus.NOT_IMPLEMENTED,\n );\n }\n await revokeAccessiUserSessions(this.options, user.codiceUtente);\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) clearAccessiAuthCookies(res, cookieConfig);\n return RestUtilities.sendOKMessage(res, 'Sessioni revocate con successo.');\n } catch (error) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.BAD_REQUEST,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Revoca un singolo access token tramite jti',\n operationId: 'revokeToken',\n description:\n 'Annulla un solo token (logout del dispositivo corrente o token compromesso) senza toccare le altre sessioni. ' +\n 'Se il body non contiene jti viene revocato il token della richiesta. Richiede accessTokenRevocation.store configurato.',\n })\n @ApiBody({ type: RevokeTokenRequest })\n @ApiOkResponse({ type: ActionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Non autorizzato a revocare il token indicato.' })\n @ApiResponse({ status: 501, type: ErrorResponse, description: 'Revoca token non configurata.' })\n @UseGuards(JwtSimpleGuard)\n @Post('revoke-token')\n async revokeToken(\n @Req() request: Request,\n @Body() body: RevokeTokenRequest,\n @Res() res: Response,\n ) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n if (!getAccessTokenRevocationStore(this.options)) {\n throw new HttpException(\n {\n code: 'ACCESSI_ACCESS_TOKEN_REVOCATION_DISABLED',\n message: 'La revoca dei singoli token non e configurata su questa istanza.',\n },\n HttpStatus.NOT_IMPLEMENTED,\n );\n }\n\n const payload = ((request as Request & { user?: unknown }).user ?? {}) as Record<string, unknown>;\n const currentJti = typeof payload.jti === 'string' ? payload.jti : undefined;\n const requestedJti = typeof body?.jti === 'string' ? body.jti.trim() : '';\n const targetJti = requestedJti !== '' ? requestedJti : currentJti;\n\n if (!targetJti) {\n throw new HttpException(\n { code: 'ACCESSI_TOKEN_JTI_MISSING', message: 'Il token non contiene un jti revocabile.' },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n const isCurrentToken = targetJti === currentJti;\n if (!isCurrentToken && !user.flagAdmin && !user.flagSuper) {\n throw new HttpException(\n {\n code: 'ACCESSI_TOKEN_REVOKE_FORBIDDEN',\n message: 'Solo gli amministratori possono revocare il token di un altro utente.',\n },\n HttpStatus.FORBIDDEN,\n );\n }\n\n const expiresAt = Number(payload.exp);\n await revokeAccessiAccessToken(\n this.options,\n targetJti,\n isCurrentToken && Number.isFinite(expiresAt) ? expiresAt * 1000 : undefined,\n );\n auditAccessi('access_token_revoked', {\n codiceUtente: user.codiceUtente,\n actor: user.codiceUtente,\n jti: targetJti,\n self: isCurrentToken,\n });\n if (isCurrentToken) {\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) clearAccessiAuthCookies(res, cookieConfig);\n }\n return RestUtilities.sendOKMessage(res, 'Token revocato con successo.');\n } catch (error) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.BAD_REQUEST,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Effettua il login utente',\n description:\n \"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.\",\n operationId: 'login',\n })\n @ApiBody({ type: LoginRequest })\n @ApiResponse({\n status: 200,\n description: 'Login effettuato con successo',\n type: LoginResponse,\n })\n @ApiResponse({\n status: 401,\n description: 'Credenziali non valide',\n type: ErrorResponse,\n })\n @ApiResponse({\n status: 403,\n description: 'Password scaduta, e necessario aggiornarla.',\n type: PasswordExpiredResponse,\n })\n @ApiResponse({ status: 403, description: 'Utente abilitato solo a SSO.', type: ErrorResponse })\n @Post('login')\n async login(@Req() request: Request, @Body() loginRequest: LoginRequest, @Res() res: Response) {\n const startedAt = Date.now();\n try {\n const rateLimitDecision = await checkPublicAuthRateLimit(\n this.options,\n 'login',\n request,\n [loginRequest?.email],\n );\n if (!rateLimitDecision.allowed) {\n countAccessiMetric(this.options, 'auth_login_total', { result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, rateLimitDecision.retryAfterSeconds);\n }\n\n const userData = await this.authService.login(loginRequest);\n if (!userData) {\n countAccessiMetric(this.options, 'auth_login_total', { result: 'failure' });\n auditAccessi('login_failed', { result: 'failure', ip: request.ip, emailProvided: Boolean(loginRequest?.email) });\n return RestUtilities.sendInvalidCredentials(res);\n }\n\n if (!userData.challenge && !userData.passwordRequired) {\n const tokens = this.authService.createTokenPair(userData.utente, ['password']);\n userData.token = tokens.access;\n if (tokens.refresh) userData.refreshToken = tokens.refresh;\n applyAccessiAuthCookies(res, resolveAccessiAuthCookieOptions(this.options), userData);\n }\n\n const result = userData.challenge\n ? 'challenge'\n : userData.passwordRequired\n ? 'password_required'\n : 'success';\n countAccessiMetric(this.options, 'auth_login_total', { result });\n if (result === 'success') {\n auditAccessi('login_succeeded', {\n codiceUtente: userData.utente?.codiceUtente,\n ip: request.ip,\n });\n }\n return RestUtilities.sendBaseResponse(res, userData);\n } catch (error) {\n const message = (error as Error)?.message;\n const result = message === 'PASSWORD_EXPIRED'\n ? 'password_expired'\n : message === PASSWORD_LOGIN_DISABLED\n ? 'sso_only'\n : 'error';\n countAccessiMetric(this.options, 'auth_login_total', { result });\n auditAccessi('login_failed', { result, ip: request.ip, emailProvided: Boolean(loginRequest?.email) });\n if (message === 'PASSWORD_EXPIRED') {\n this.logger.warning('Password scaduta, cambiare password ', error);\n return RestUtilities.sendPasswordExpired(res);\n }\n\n if (error instanceof HttpException) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error.getStatus());\n }\n\n if ((error as Error)?.message === PASSWORD_LOGIN_DISABLED) {\n return res.status(HttpStatus.FORBIDDEN).json({\n severity: 'error', status: HttpStatus.FORBIDDEN, statusCode: 2,\n code: PASSWORD_LOGIN_DISABLED,\n error: PASSWORD_LOGIN_DISABLED,\n message: 'Questo utente e abilitato solo tramite SSO. Accedi con un provider collegato.',\n });\n }\n\n this.logger.error('Errore durante il login', error);\n if (RestUtilities.isDatabaseSchemaError(error)) {\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n HttpStatus.SERVICE_UNAVAILABLE,\n );\n }\n return RestUtilities.sendInvalidCredentials(res);\n } finally {\n observeAccessiMetric(this.options, 'auth_login_duration_ms', Date.now() - startedAt);\n }\n }\n\n @ApiOperation({\n summary: 'Scambia un refresh token con un nuovo access token',\n operationId: 'refreshAccessToken',\n description:\n 'Richiede jwtOptions.refreshExpiresIn. Il refresh token ha typ=refresh e non e accettato dai guard API.',\n })\n @ApiBody({ type: RefreshTokenRequest })\n @ApiOkResponse({ type: RefreshTokenResponse })\n @ApiResponse({ status: 401, description: 'Refresh token non valido, scaduto o revocato.', type: ErrorResponse })\n @ApiResponse({ status: 429, description: 'Troppi tentativi.', type: ErrorResponse })\n @Post('refresh')\n async refresh(\n @Req() request: Request,\n @Body() body: RefreshTokenRequest,\n @Res() res: Response,\n ) {\n const startedAt = Date.now();\n try {\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n const cookieRefreshToken = cookieConfig?.refreshFromCookie\n ? getAccessiRefreshTokenFromCookie(request.headers.cookie, cookieConfig)\n : undefined;\n const refreshToken = typeof body?.refreshToken === 'string' && body.refreshToken.trim() !== ''\n ? body.refreshToken\n : cookieRefreshToken;\n const tokenKey = typeof refreshToken === 'string'\n ? createHash('sha256').update(refreshToken).digest('hex').slice(0, 32)\n : undefined;\n const decision = await checkPublicAuthRateLimit(\n this.options,\n 'refresh',\n request,\n tokenKey ? [tokenKey] : [],\n );\n if (!decision.allowed) {\n countAccessiMetric(this.options, 'auth_refresh_total', { result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, decision.retryAfterSeconds);\n }\n\n if (!refreshToken) {\n throw new HttpException('Refresh token mancante.', HttpStatus.UNAUTHORIZED);\n }\n\n const result = await this.authService.refreshAccessToken(refreshToken);\n if (!result.token) {\n throw new HttpException('Refresh token non valido.', HttpStatus.UNAUTHORIZED);\n }\n const response = {\n token: result.token,\n ...(result.refreshToken ? { refreshToken: result.refreshToken } : {}),\n };\n applyAccessiAuthCookies(res, cookieConfig, response);\n countAccessiMetric(this.options, 'auth_refresh_total', { result: 'success' });\n auditAccessi('refresh_succeeded', { ip: request.ip });\n return RestUtilities.sendBaseResponse(res, response);\n } catch (error) {\n const code = authErrorCode(error);\n const result = code === 'ACCESSI_REFRESH_TOKEN_REUSE'\n ? 'reuse'\n : code === 'ACCESSI_REFRESH_FAMILY_REVOKED'\n ? 'family_revoked'\n : code === 'ACCESSI_REFRESH_ROTATION_UNAVAILABLE'\n ? 'store_unavailable'\n : 'invalid';\n countAccessiMetric(this.options, 'auth_refresh_total', { result });\n if (result !== 'reuse') auditAccessi('refresh_failed', { result, ip: request.ip });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n AuthController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n } finally {\n observeAccessiMetric(this.options, 'auth_refresh_duration_ms', Date.now() - startedAt);\n }\n }\n\n @Post('two-factor/verify')\n @ApiOperation({ summary: 'Verifica il codice e completa il login', operationId: 'verifyTwoFactor' })\n @ApiBody({ type: VerifyTwoFactorRequest })\n @ApiResponse({ status: 200, type: LoginResponse })\n @ApiResponse({ status: 401, type: ErrorResponse })\n @ApiResponse({ status: 429, type: ErrorResponse })\n async verifyTwoFactor(@Req() request: Request, @Body() body: VerifyTwoFactorRequest, @Res() res: Response) {\n const startedAt = Date.now();\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'twoFactorVerify', request, [body.challengeId]);\n if (!limit.allowed) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n }\n const result = await this.authService.verifyTwoFactor(body.challengeId, body.code, body.scope);\n applyAccessiAuthCookies(res, resolveAccessiAuthCookieOptions(this.options), result);\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'success' });\n auditAccessi('two_factor_succeeded', { codiceUtente: result.utente?.codiceUtente, ip: request.ip });\n return RestUtilities.sendBaseResponse(res, result);\n } catch (error) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'verify', result: 'failure' });\n auditAccessi('two_factor_failed', { ip: request.ip });\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n } finally {\n observeAccessiMetric(this.options, 'auth_two_factor_duration_ms', Date.now() - startedAt, { action: 'verify' });\n }\n }\n\n @Post('two-factor/resend')\n @ApiOperation({ summary: 'Reinvia il codice, invalidando il precedente', operationId: 'resendTwoFactor' })\n @ApiBody({ type: ResendTwoFactorRequest })\n @ApiResponse({ status: 200, type: LoginResponse })\n @ApiResponse({ status: 401, type: ErrorResponse })\n @ApiResponse({ status: 429, type: ErrorResponse })\n async resendTwoFactor(@Req() request: Request, @Body() body: ResendTwoFactorRequest, @Res() res: Response) {\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'twoFactorResend', request, [body.challengeId]);\n if (!limit.allowed) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n }\n const result = await this.authService.resendTwoFactor(body.challengeId);\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'success' });\n return RestUtilities.sendBaseResponse(res, result);\n } catch (error) {\n countAccessiMetric(this.options, 'auth_two_factor_total', { action: 'resend', result: 'failure' });\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n }\n }\n\n @Post('bootstrap-admin')\n @ApiOperation({\n summary: 'Crea il primo utente admin (bootstrap)',\n operationId: 'bootstrapAdmin',\n description:\n 'Endpoint pubblico ma protetto dal token di avvio: attivo solo con adminBootstrap.enabled. ' +\n 'Crea un utente in stato confermato senza email, con flag admin (e super opzionale) e password fornita o generata.',\n })\n @ApiBody({ type: BootstrapAdminRequest })\n @ApiResponse({ status: 200, type: BootstrapAdminResponse })\n @ApiResponse({ status: 401, description: 'Token di bootstrap non valido', type: ErrorResponse })\n @ApiResponse({ status: 403, description: 'Bootstrap admin non abilitato', type: ErrorResponse })\n @ApiResponse({ status: 429, description: 'Troppi tentativi', type: ErrorResponse })\n async bootstrapAdmin(@Req() request: Request, @Body() body: BootstrapAdminRequest, @Res() res: Response) {\n try {\n const limit = await checkPublicAuthRateLimit(this.options, 'adminBootstrap', request);\n if (!limit.allowed) return sendPublicAuthRateLimitExceeded(res, limit.retryAfterSeconds);\n return RestUtilities.sendBaseResponse(res, await this.adminBootstrapService.bootstrap(body));\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, AuthController.name, error instanceof HttpException ? error.getStatus() : 500);\n }\n }\n\n @Get('bootstrap-admin/status')\n @ApiOperation({\n summary: 'Indica se il bootstrap admin e abilitato',\n operationId: 'getAdminBootstrapStatus',\n description:\n 'Endpoint pubblico: la console mostra la sezione \"Crea utente admin\" solo quando enabled e true.',\n })\n @ApiResponse({ status: 200, type: AdminBootstrapStatusResponse })\n async adminBootstrapStatus(@Res() res: Response) {\n return RestUtilities.sendBaseResponse(res, { enabled: this.adminBootstrapService.isEnabled() });\n }\n}\n"]}
|
|
@@ -35,6 +35,7 @@ const consoleEntry_1 = require("../security/consoleEntry");
|
|
|
35
35
|
const publicAuthRateLimit_1 = require("../security/publicAuthRateLimit");
|
|
36
36
|
const authCookies_1 = require("../security/authCookies");
|
|
37
37
|
const metrics_1 = require("../observability/metrics");
|
|
38
|
+
const audit_1 = require("../security/audit");
|
|
38
39
|
/**
|
|
39
40
|
* Auto-ingresso alla console amministrativa da un frontend gia autenticato.
|
|
40
41
|
* Il frontend scambia la propria sessione Accessi con un ticket monouso, poi apre
|
|
@@ -63,6 +64,7 @@ let ConsoleEntryController = ConsoleEntryController_1 = class ConsoleEntryContro
|
|
|
63
64
|
}
|
|
64
65
|
const issued = yield this.store.issue({ token: tokenValue, codiceUtente: user.codiceUtente }, this.ttlMs);
|
|
65
66
|
(0, metrics_1.countAccessiMetric)(this.options, 'console_ticket_total', { action: 'create', result: 'issued' });
|
|
67
|
+
(0, audit_1.auditAccessi)('console_ticket_issued', { codiceUtente: user.codiceUtente });
|
|
66
68
|
return Utilities_1.RestUtilities.sendBaseResponse(res, issued);
|
|
67
69
|
}
|
|
68
70
|
catch (error) {
|
|
@@ -88,6 +90,7 @@ let ConsoleEntryController = ConsoleEntryController_1 = class ConsoleEntryContro
|
|
|
88
90
|
});
|
|
89
91
|
}
|
|
90
92
|
(0, metrics_1.countAccessiMetric)(this.options, 'console_ticket_total', { action: 'exchange', result: 'consumed' });
|
|
93
|
+
(0, audit_1.auditAccessi)('console_ticket_consumed', { codiceUtente: entry.codiceUtente });
|
|
91
94
|
const cookieConfig = (0, authCookies_1.resolveAccessiAuthCookieOptions)(this.options);
|
|
92
95
|
if (cookieConfig) {
|
|
93
96
|
(0, authCookies_1.setAccessiAuthCookies)(res, cookieConfig, { access: entry.token });
|
|
@@ -102,6 +105,9 @@ let ConsoleEntryController = ConsoleEntryController_1 = class ConsoleEntryContro
|
|
|
102
105
|
action: 'exchange',
|
|
103
106
|
result: error instanceof common_1.UnauthorizedException ? 'invalid' : 'error',
|
|
104
107
|
});
|
|
108
|
+
(0, audit_1.auditAccessi)('console_ticket_failed', {
|
|
109
|
+
result: error instanceof common_1.UnauthorizedException ? 'invalid' : 'error',
|
|
110
|
+
});
|
|
105
111
|
return Utilities_1.RestUtilities.sendErrorMessage(res, error, ConsoleEntryController_1.name, error instanceof common_1.HttpException ? error.getStatus() : common_1.HttpStatus.UNAUTHORIZED);
|
|
106
112
|
}
|
|
107
113
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsoleEntryController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/ConsoleEntryController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Body,\n Controller,\n HttpException,\n HttpStatus,\n Inject,\n Post,\n Req,\n Res,\n UnauthorizedException,\n UseGuards,\n} from '@nestjs/common';\nimport {\n ApiBearerAuth,\n ApiBody,\n ApiOkResponse,\n ApiOperation,\n ApiResponse,\n ApiTags,\n} from '@nestjs/swagger';\nimport { Request, Response } from 'express';\nimport { RestUtilities } from '../../Utilities';\nimport type { AccessiOptions } from '../AccessiModule';\nimport { ConsoleEntryExchangeRequest, ConsoleEntrySessionResponse, ConsoleEntryTicketResponse } from '../Dtos/ConsoleEntryDtos';\nimport { ErrorResponse } from '../Dtos/BaseResponse';\nimport { JwtSimpleGuard } from '../jwt/jwt.strategy';\nimport { ensureConsoleAccess, getAuthenticatedAccessiUser } from '../security/accessControl';\nimport { extractAccessiBearerToken } from '../security/authenticatedToken';\nimport { getDefaultConsoleEntryStore } from '../security/consoleEntry';\nimport type { ConsoleEntryStore } from '../security/consoleEntry';\nimport {\n checkPublicAuthRateLimit,\n sendPublicAuthRateLimitExceeded,\n} from '../security/publicAuthRateLimit';\nimport {\n resolveAccessiAuthCookieOptions,\n setAccessiAuthCookies,\n} from '../security/authCookies';\nimport { countAccessiMetric } from '../observability/metrics';\n\n/**\n * Auto-ingresso alla console amministrativa da un frontend gia autenticato.\n * Il frontend scambia la propria sessione Accessi con un ticket monouso, poi apre\n * `/api/accessi/console#entry=<ticket>`: il JWT non passa mai nell'URL.\n */\n@ApiTags('Console')\n@ApiBearerAuth()\n@Controller('accessi/console')\nexport class ConsoleEntryController {\n constructor(@Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions) {}\n\n private get store(): ConsoleEntryStore {\n return this.options.consoleEntry?.store ?? getDefaultConsoleEntryStore();\n }\n\n private get ttlMs(): number {\n return this.options.consoleEntry?.ttlMs ?? 60_000;\n }\n\n @ApiOperation({\n summary: 'Emetti un ticket di ingresso alla console',\n operationId: 'createConsoleEntryTicket',\n description: 'Riservato agli utenti abilitati alla console (FLGSUPER/FLGADMIN). Restituisce un ticket monouso legato all utente, valido pochi secondi.',\n })\n @ApiOkResponse({ type: ConsoleEntryTicketResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Utente non abilitato alla console.' })\n @UseGuards(JwtSimpleGuard)\n @Post('entry')\n async createEntryTicket(@Req() request: Request, @Res() res: Response) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n ensureConsoleAccess(user);\n\n const tokenValue = extractAccessiBearerToken(request.headers['authorization']);\n if (!tokenValue) {\n throw new UnauthorizedException({ code: 'ACCESSI_CONSOLE_ENTRY_TOKEN_MISSING', message: 'Token Accessi mancante.' });\n }\n\n const issued = await this.store.issue(\n { token: tokenValue, codiceUtente: user.codiceUtente },\n this.ttlMs,\n );\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'create', result: 'issued' });\n return RestUtilities.sendBaseResponse(res, issued);\n } catch (error) {\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'create', result: 'error' });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n ConsoleEntryController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Scambia il ticket con la sessione Accessi',\n operationId: 'exchangeConsoleEntryTicket',\n description: 'Endpoint pubblico (il ticket e l unica credenziale) protetto da rate limit; il ticket e monouso e scade in pochi secondi.',\n })\n @ApiBody({ type: ConsoleEntryExchangeRequest })\n @ApiOkResponse({ type: ConsoleEntrySessionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Ticket non valido o scaduto.' })\n @ApiResponse({ status: 429, type: ErrorResponse, description: 'Troppi tentativi.' })\n @Post('entry/exchange')\n async exchangeEntryTicket(\n @Req() request: Request,\n @Body() body: ConsoleEntryExchangeRequest,\n @Res() res: Response,\n ) {\n try {\n const decision = await checkPublicAuthRateLimit(this.options, 'consoleEntry', request, [body?.ticket ?? '']);\n if (!decision.allowed) {\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'exchange', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, decision.retryAfterSeconds);\n }\n\n const entry = await this.store.consume(body?.ticket);\n if (!entry) {\n throw new UnauthorizedException({\n code: 'ACCESSI_CONSOLE_ENTRY_INVALID',\n message: 'Ticket di ingresso console non valido o scaduto. Riapri la console dal frontend.',\n });\n }\n\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'exchange', result: 'consumed' });\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) {\n setAccessiAuthCookies(res, cookieConfig, { access: entry.token });\n if (!cookieConfig.exposeTokens) {\n return RestUtilities.sendBaseResponse(res, {});\n }\n }\n return RestUtilities.sendBaseResponse(res, { token: { value: entry.token, type: 'Bearer' } });\n } catch (error) {\n countAccessiMetric(this.options, 'console_ticket_total', {\n action: 'exchange',\n result: error instanceof UnauthorizedException ? 'invalid' : 'error',\n });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n ConsoleEntryController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ConsoleEntryController.js","sourceRoot":"","sources":["../../../src/accessi-module/Controllers/ConsoleEntryController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Body,\n Controller,\n HttpException,\n HttpStatus,\n Inject,\n Post,\n Req,\n Res,\n UnauthorizedException,\n UseGuards,\n} from '@nestjs/common';\nimport {\n ApiBearerAuth,\n ApiBody,\n ApiOkResponse,\n ApiOperation,\n ApiResponse,\n ApiTags,\n} from '@nestjs/swagger';\nimport { Request, Response } from 'express';\nimport { RestUtilities } from '../../Utilities';\nimport type { AccessiOptions } from '../AccessiModule';\nimport { ConsoleEntryExchangeRequest, ConsoleEntrySessionResponse, ConsoleEntryTicketResponse } from '../Dtos/ConsoleEntryDtos';\nimport { ErrorResponse } from '../Dtos/BaseResponse';\nimport { JwtSimpleGuard } from '../jwt/jwt.strategy';\nimport { ensureConsoleAccess, getAuthenticatedAccessiUser } from '../security/accessControl';\nimport { extractAccessiBearerToken } from '../security/authenticatedToken';\nimport { getDefaultConsoleEntryStore } from '../security/consoleEntry';\nimport type { ConsoleEntryStore } from '../security/consoleEntry';\nimport {\n checkPublicAuthRateLimit,\n sendPublicAuthRateLimitExceeded,\n} from '../security/publicAuthRateLimit';\nimport {\n resolveAccessiAuthCookieOptions,\n setAccessiAuthCookies,\n} from '../security/authCookies';\nimport { countAccessiMetric } from '../observability/metrics';\nimport { auditAccessi } from '../security/audit';\n\n/**\n * Auto-ingresso alla console amministrativa da un frontend gia autenticato.\n * Il frontend scambia la propria sessione Accessi con un ticket monouso, poi apre\n * `/api/accessi/console#entry=<ticket>`: il JWT non passa mai nell'URL.\n */\n@ApiTags('Console')\n@ApiBearerAuth()\n@Controller('accessi/console')\nexport class ConsoleEntryController {\n constructor(@Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions) {}\n\n private get store(): ConsoleEntryStore {\n return this.options.consoleEntry?.store ?? getDefaultConsoleEntryStore();\n }\n\n private get ttlMs(): number {\n return this.options.consoleEntry?.ttlMs ?? 60_000;\n }\n\n @ApiOperation({\n summary: 'Emetti un ticket di ingresso alla console',\n operationId: 'createConsoleEntryTicket',\n description: 'Riservato agli utenti abilitati alla console (FLGSUPER/FLGADMIN). Restituisce un ticket monouso legato all utente, valido pochi secondi.',\n })\n @ApiOkResponse({ type: ConsoleEntryTicketResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Token Accessi mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Utente non abilitato alla console.' })\n @UseGuards(JwtSimpleGuard)\n @Post('entry')\n async createEntryTicket(@Req() request: Request, @Res() res: Response) {\n try {\n const user = getAuthenticatedAccessiUser(request);\n ensureConsoleAccess(user);\n\n const tokenValue = extractAccessiBearerToken(request.headers['authorization']);\n if (!tokenValue) {\n throw new UnauthorizedException({ code: 'ACCESSI_CONSOLE_ENTRY_TOKEN_MISSING', message: 'Token Accessi mancante.' });\n }\n\n const issued = await this.store.issue(\n { token: tokenValue, codiceUtente: user.codiceUtente },\n this.ttlMs,\n );\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'create', result: 'issued' });\n auditAccessi('console_ticket_issued', { codiceUtente: user.codiceUtente });\n return RestUtilities.sendBaseResponse(res, issued);\n } catch (error) {\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'create', result: 'error' });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n ConsoleEntryController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n }\n }\n\n @ApiOperation({\n summary: 'Scambia il ticket con la sessione Accessi',\n operationId: 'exchangeConsoleEntryTicket',\n description: 'Endpoint pubblico (il ticket e l unica credenziale) protetto da rate limit; il ticket e monouso e scade in pochi secondi.',\n })\n @ApiBody({ type: ConsoleEntryExchangeRequest })\n @ApiOkResponse({ type: ConsoleEntrySessionResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Ticket non valido o scaduto.' })\n @ApiResponse({ status: 429, type: ErrorResponse, description: 'Troppi tentativi.' })\n @Post('entry/exchange')\n async exchangeEntryTicket(\n @Req() request: Request,\n @Body() body: ConsoleEntryExchangeRequest,\n @Res() res: Response,\n ) {\n try {\n const decision = await checkPublicAuthRateLimit(this.options, 'consoleEntry', request, [body?.ticket ?? '']);\n if (!decision.allowed) {\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'exchange', result: 'rate_limited' });\n return sendPublicAuthRateLimitExceeded(res, decision.retryAfterSeconds);\n }\n\n const entry = await this.store.consume(body?.ticket);\n if (!entry) {\n throw new UnauthorizedException({\n code: 'ACCESSI_CONSOLE_ENTRY_INVALID',\n message: 'Ticket di ingresso console non valido o scaduto. Riapri la console dal frontend.',\n });\n }\n\n countAccessiMetric(this.options, 'console_ticket_total', { action: 'exchange', result: 'consumed' });\n auditAccessi('console_ticket_consumed', { codiceUtente: entry.codiceUtente });\n const cookieConfig = resolveAccessiAuthCookieOptions(this.options);\n if (cookieConfig) {\n setAccessiAuthCookies(res, cookieConfig, { access: entry.token });\n if (!cookieConfig.exposeTokens) {\n return RestUtilities.sendBaseResponse(res, {});\n }\n }\n return RestUtilities.sendBaseResponse(res, { token: { value: entry.token, type: 'Bearer' } });\n } catch (error) {\n countAccessiMetric(this.options, 'console_ticket_total', {\n action: 'exchange',\n result: error instanceof UnauthorizedException ? 'invalid' : 'error',\n });\n auditAccessi('console_ticket_failed', {\n result: error instanceof UnauthorizedException ? 'invalid' : 'error',\n });\n return RestUtilities.sendErrorMessage(\n res,\n error,\n ConsoleEntryController.name,\n error instanceof HttpException ? error.getStatus() : HttpStatus.UNAUTHORIZED,\n );\n }\n }\n}\n"]}
|