skailan-core
Version:
Servicio de autenticación y multitenancy para Skailan.
473 lines • 15.2 kB
JavaScript
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