feat: auditoría (audit_log en SQLite, endpoint /api/audit y pantalla /admin/auditoria)
Registra sesiones, creaciones y modificaciones en SAP (solo nombres de campos), denegados y cambios de permisos. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e9d6a757d
commit
fe8c080471
26 files changed
+993
-28
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { Body, Controller, Delete, Get, HttpCode, Param, Put, Req, UseGuards } from '@nestjs/common';
|
||||
import { z } from 'zod';
|
||||
import { AuditService } from '../audit/audit.service.js';
|
||||
import type { AuthenticatedRequest } from '../auth/auth.types.js';
|
||||
import { ZodValidationPipe } from '../common/zod-validation.pipe.js';
|
||||
import { AdminGuard } from './admin.guard.js';
|
||||
@@ -29,7 +30,10 @@ export class UserMenuController {
|
||||
@Controller('permissions')
|
||||
@UseGuards(AdminGuard)
|
||||
export class PermissionsController {
|
||||
constructor(private readonly permissions: PermissionsService) {}
|
||||
constructor(
|
||||
private readonly permissions: PermissionsService,
|
||||
private readonly audit: AuditService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
list() {
|
||||
@@ -42,16 +46,30 @@ export class PermissionsController {
|
||||
}
|
||||
|
||||
@Put(':webUser')
|
||||
set(
|
||||
async set(
|
||||
@Req() req: AuthenticatedRequest,
|
||||
@Param('webUser', new ZodValidationPipe(webUserSchema)) webUser: string,
|
||||
@Body(new ZodValidationPipe(setPathsSchema)) body: SetPathsDto,
|
||||
) {
|
||||
return this.permissions.setPaths(webUser, body.paths);
|
||||
try {
|
||||
const result = await this.permissions.setPaths(webUser, body.paths);
|
||||
await this.audit.record({ action: 'permissions_set', webUser: req.user.webUser, ip: req.ip, resource: webUser, detail: { paths: body.paths } });
|
||||
return result;
|
||||
} catch (e) {
|
||||
await this.audit.record({ action: 'permissions_set', webUser: req.user.webUser, ip: req.ip, resource: webUser, outcome: 'error', detail: { paths: body.paths, error: e instanceof Error ? e.message : String(e) } });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':webUser')
|
||||
@HttpCode(204)
|
||||
remove(@Param('webUser', new ZodValidationPipe(webUserSchema)) webUser: string) {
|
||||
return this.permissions.remove(webUser);
|
||||
async remove(@Req() req: AuthenticatedRequest, @Param('webUser', new ZodValidationPipe(webUserSchema)) webUser: string) {
|
||||
try {
|
||||
await this.permissions.remove(webUser);
|
||||
await this.audit.record({ action: 'permissions_remove', webUser: req.user.webUser, ip: req.ip, resource: webUser });
|
||||
} catch (e) {
|
||||
await this.audit.record({ action: 'permissions_remove', webUser: req.user.webUser, ip: req.ip, resource: webUser, outcome: 'error', detail: { error: e instanceof Error ? e.message : String(e) } });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AuditModule } from '../audit/audit.module.js';
|
||||
import { AdminGuard } from './admin.guard.js';
|
||||
import { MenuPermission } from './menu-permission.entity.js';
|
||||
import { PermissionsController, UserMenuController } from './permissions.controller.js';
|
||||
import { PermissionsService } from './permissions.service.js';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([MenuPermission])],
|
||||
imports: [TypeOrmModule.forFeature([MenuPermission]), AuditModule],
|
||||
controllers: [UserMenuController, PermissionsController],
|
||||
providers: [PermissionsService, AdminGuard],
|
||||
exports: [PermissionsService],
|
||||
|
||||
Reference in new issue
Block a user