UNPKG

skailan-core

Version:

Servicio de autenticación y multitenancy para Skailan.

473 lines 15.2 kB
import { Router } from "express"; import { PrismaClient } from "@prisma/client"; import { PermissionService } from "../../shared/services/PermissionService"; import { RBACService } from "../../shared/services/RBACService"; import { requirePermission, requireRole, auditPermission, } from "../../shared/middlewares/rbacMiddleware"; const router = Router(); // Inicializar servicios let permissionService; let rbacService; // Middleware para inicializar servicios router.use((req, res, next) => { const prisma = req.tenantPrisma || new PrismaClient(); if (!permissionService) { permissionService = new PermissionService(prisma); } if (!rbacService) { rbacService = new RBACService(prisma); } next(); }); // ===== RUTAS DE PERMISOS ===== /** * GET /rbac/permissions * Obtener todos los permisos de la organización */ router.get("/permissions", requirePermission("permissions", "read"), auditPermission("permissions", "read"), async (req, res) => { try { const organization = req.organization; const permissions = await permissionService.getPermissions(organization.id); res.json({ success: true, data: permissions, total: permissions.length, }); } catch (error) { console.error("Error obteniendo permisos:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * POST /rbac/permissions * Crear un nuevo permiso */ router.post("/permissions", requirePermission("permissions", "manage"), auditPermission("permissions", "create"), async (req, res) => { try { const { resource, action, description } = req.body; const organization = req.organization; if (!resource || !action) { return res.status(400).json({ success: false, error: "Resource y action son requeridos", }); } const permission = await permissionService.createPermission({ resource, action, description }, organization.id); res.status(201).json({ success: true, data: permission, message: "Permiso creado exitosamente", }); } catch (error) { console.error("Error creando permiso:", error); res.status(500).json({ success: false, error: error instanceof Error ? error.message : "Error interno del servidor", }); } }); /** * GET /rbac/permissions/:id * Obtener un permiso específico */ router.get("/permissions/:id", requirePermission("permissions", "read"), async (req, res) => { try { const { id } = req.params; if (!id) { return res.status(400).json({ success: false, error: "ID is required", }); } const permission = await permissionService.getPermissionById(id); if (!permission) { return res.status(404).json({ success: false, error: "Permiso no encontrado", }); } res.json({ success: true, data: permission, }); } catch (error) { console.error("Error obteniendo permiso:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * PUT /rbac/permissions/:id * Actualizar un permiso */ router.put("/permissions/:id", requirePermission("permissions", "manage"), auditPermission("permissions", "update"), async (req, res) => { try { const { id } = req.params; if (!id) { return res.status(400).json({ success: false, error: "ID is required", }); } const { resource, action, description } = req.body; const permission = await permissionService.updatePermission(id, { resource, action, description, }); res.json({ success: true, data: permission, message: "Permiso actualizado exitosamente", }); } catch (error) { console.error("Error actualizando permiso:", error); res.status(500).json({ success: false, error: error instanceof Error ? error.message : "Error interno del servidor", }); } }); /** * DELETE /rbac/permissions/:id * Eliminar un permiso */ router.delete("/permissions/:id", requirePermission("permissions", "manage"), auditPermission("permissions", "delete"), async (req, res) => { try { const { id } = req.params; if (!id) { return res.status(400).json({ success: false, error: "ID is required", }); } await permissionService.deletePermission(id); res.json({ success: true, message: "Permiso eliminado exitosamente", }); } catch (error) { console.error("Error eliminando permiso:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); // ===== RUTAS DE ASIGNACIÓN DE PERMISOS ===== /** * GET /rbac/roles/:role/permissions * Obtener permisos de un rol específico */ router.get("/roles/:role/permissions", requirePermission("permissions", "read"), async (req, res) => { try { const { role } = req.params; const organization = req.organization; if (!role) { return res.status(400).json({ success: false, error: "Role parameter is required", }); } if (!organization?.id) { return res.status(400).json({ success: false, error: "Organization ID is required", }); } const organizationId = organization.id; if (!organizationId) { return res.status(400).json({ success: false, error: "Organization ID is required", }); } const permissions = await permissionService.getRolePermissions(role, organizationId); res.json({ success: true, data: permissions, role, total: permissions.length, }); } catch (error) { console.error("Error obteniendo permisos del rol:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * POST /rbac/roles/:role/permissions * Asignar un permiso a un rol */ router.post("/roles/:role/permissions", requirePermission("permissions", "manage"), auditPermission("permissions", "manage"), async (req, res) => { try { const { role } = req.params; const { permissionId } = req.body; const organization = req.organization; if (!role) { return res.status(400).json({ success: false, error: "Role parameter is required", }); } if (!permissionId) { return res.status(400).json({ success: false, error: "PermissionId es requerido", }); } const rolePermission = await permissionService.assignPermissionToRole({ role: role, permissionId }, organization.id); res.status(201).json({ success: true, data: rolePermission, message: "Permiso asignado exitosamente", }); } catch (error) { console.error("Error asignando permiso:", error); res.status(500).json({ success: false, error: error instanceof Error ? error.message : "Error interno del servidor", }); } }); /** * DELETE /rbac/roles/:role/permissions/:permissionId * Revocar un permiso de un rol */ router.delete("/roles/:role/permissions/:permissionId", requirePermission("permissions", "manage"), auditPermission("permissions", "manage"), async (req, res) => { try { const { role, permissionId } = req.params; const organization = req.organization; if (!role) { return res.status(400).json({ success: false, error: "Role parameter is required", }); } if (!permissionId) { return res.status(400).json({ success: false, error: "PermissionId parameter is required", }); } if (!organization?.id) { return res.status(400).json({ success: false, error: "Organization ID is required", }); } const organizationId = organization.id; if (!organizationId) { return res.status(400).json({ success: false, error: "Organization ID is required", }); } await permissionService.revokePermissionFromRole(role, permissionId, organizationId); res.json({ success: true, message: "Permiso revocado exitosamente", }); } catch (error) { console.error("Error revocando permiso:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * POST /rbac/roles/:role/permissions/bulk * Asignar múltiples permisos a un rol */ router.post("/roles/:role/permissions/bulk", requirePermission("permissions", "manage"), auditPermission("permissions", "manage"), async (req, res) => { try { const { role } = req.params; const { permissions } = req.body; const organization = req.organization; if (!role) { return res.status(400).json({ success: false, error: "Role parameter is required", }); } if (!permissions || !Array.isArray(permissions)) { return res.status(400).json({ success: false, error: "Permissions debe ser un array", }); } const result = await permissionService.bulkAssignPermissions({ role: role, permissions }, organization.id); res.json({ success: true, data: result, message: `Asignación completada. ${result.success.length} exitosas, ${result.failed.length} fallidas`, }); } catch (error) { console.error("Error en asignación masiva:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); // ===== RUTAS DE VERIFICACIÓN DE PERMISOS ===== /** * POST /rbac/check-permission * Verificar si el usuario actual tiene un permiso específico */ router.post("/check-permission", async (req, res) => { try { const { resource, action } = req.body; const membership = req.membership; const organization = req.organization; if (!resource || !action) { return res.status(400).json({ success: false, error: "Resource y action son requeridos", }); } const validation = await rbacService.checkPermission(membership.userId, organization.id, resource, action); res.json({ success: true, data: validation, }); } catch (error) { console.error("Error verificando permiso:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * GET /rbac/my-permissions * Obtener todos los permisos del usuario actual */ router.get("/my-permissions", async (req, res) => { try { const membership = req.membership; const organization = req.organization; const permissions = await rbacService.getUserPermissions(membership.userId, organization.id); res.json({ success: true, data: permissions, total: permissions.length, }); } catch (error) { console.error("Error obteniendo permisos del usuario:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); // ===== RUTAS DE ADMINISTRACIÓN ===== /** * POST /rbac/setup-defaults * Configurar permisos por defecto para la organización */ router.post("/setup-defaults", requireRole(["OWNER", "ADMIN"]), auditPermission("permissions", "manage"), async (req, res) => { try { const organization = req.organization; await permissionService.createDefaultPermissions(organization.id); res.json({ success: true, message: "Permisos por defecto configurados exitosamente", }); } catch (error) { console.error("Error configurando permisos por defecto:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * GET /rbac/stats * Obtener estadísticas de permisos */ router.get("/stats", requirePermission("permissions", "read"), async (req, res) => { try { const organization = req.organization; const stats = await rbacService.getPermissionStats(organization.id); res.json({ success: true, data: stats, }); } catch (error) { console.error("Error obteniendo estadísticas:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * POST /rbac/validate-configuration * Validar la configuración de permisos */ router.post("/validate-configuration", requireRole(["OWNER", "ADMIN"]), async (req, res) => { try { const organization = req.organization; const validation = await rbacService.validatePermissionConfiguration(organization.id); res.json({ success: true, data: validation, }); } catch (error) { console.error("Error validando configuración:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); /** * POST /rbac/clear-cache * Limpiar cache de permisos */ router.post("/clear-cache", requireRole(["OWNER", "ADMIN"]), async (req, res) => { try { const { userId, organizationId } = req.body; if (userId && organizationId) { rbacService.clearCache(userId, organizationId); } else { rbacService.clearCache(); } res.json({ success: true, message: "Cache limpiado exitosamente", }); } catch (error) { console.error("Error limpiando cache:", error); res.status(500).json({ success: false, error: "Error interno del servidor", }); } }); export default router; //# sourceMappingURL=rbacRoutes.js.map