Spaces:
Build error
Build error
| // RBAC Middleware for Express/Fastify API | |
| export enum Role { | |
| CLIENT = 'CLIENT', | |
| VENDOR = 'VENDOR', | |
| ADMIN = 'ADMIN', | |
| } | |
| export enum Permission { | |
| // Client permissions | |
| VIEW_OWN_BOOKINGS = 'view_own_bookings', | |
| CREATE_BOOKING = 'create_booking', | |
| SIGN_CONTRACT = 'sign_contract', | |
| VIEW_OWN_CONTRACTS = 'view_own_contracts', | |
| REQUEST_AMENDMENT = 'request_amendment', | |
| // Vendor permissions | |
| MANAGE_PROFILE = 'manage_profile', | |
| MANAGE_PACKAGES = 'manage_packages', | |
| VIEW_LEADS = 'view_leads', | |
| CREATE_CONTRACT = 'create_contract', | |
| SEND_CONTRACT = 'send_contract', | |
| MANAGE_DELIVERABLES = 'manage_deliverables', | |
| // Admin permissions | |
| MODERATE_VENDORS = 'moderate_vendors', | |
| MODERATE_CONTENT = 'moderate_content', | |
| OVERSEE_CONTRACTS = 'oversee_contracts', | |
| MEDIATE_DISPUTES = 'mediate_disputes', | |
| EXPORT_AUDIT_TRAIL = 'export_audit_trail', | |
| MANAGE_CATEGORIES = 'manage_categories', | |
| IMPERSONATE_USERS = 'impersonate_users', | |
| MANAGE_USERS = 'manage_users', | |
| } | |
| const rolePermissions: Record<Role, Permission[]> = { | |
| [Role.CLIENT]: [ | |
| Permission.VIEW_OWN_BOOKINGS, | |
| Permission.CREATE_BOOKING, | |
| Permission.SIGN_CONTRACT, | |
| Permission.VIEW_OWN_CONTRACTS, | |
| Permission.REQUEST_AMENDMENT, | |
| ], | |
| [Role.VENDOR]: [ | |
| Permission.MANAGE_PROFILE, | |
| Permission.MANAGE_PACKAGES, | |
| Permission.VIEW_LEADS, | |
| Permission.CREATE_CONTRACT, | |
| Permission.SEND_CONTRACT, | |
| Permission.MANAGE_DELIVERABLES, | |
| ], | |
| [Role.ADMIN]: Object.values(Permission), | |
| } | |
| export function hasPermission(role: Role, permission: Permission): boolean { | |
| return rolePermissions[role]?.includes(permission) ?? false | |
| } | |
| export function requirePermission(permission: Permission) { | |
| return function (req: any, res: any, next: Function) { | |
| const role = req.user?.role as Role | |
| if (!role || !hasPermission(role, permission)) { | |
| return res.status(403).json({ | |
| error: 'Forbidden', | |
| message: `Missing required permission: ${permission}`, | |
| }) | |
| } | |
| next() | |
| } | |
| } | |
| export function requireRole(...roles: Role[]) { | |
| return function (req: any, res: any, next: Function) { | |
| const role = req.user?.role as Role | |
| if (!role || !roles.includes(role)) { | |
| return res.status(403).json({ | |
| error: 'Forbidden', | |
| message: `Access restricted to: ${roles.join(', ')}`, | |
| }) | |
| } | |
| next() | |
| } | |
| } | |
| // Contract-specific RBAC: only the vendor who created it or the client who received it can access | |
| export function requireContractAccess(contractIdParam: string = 'contractId') { | |
| return async function (req: any, res: any, next: Function) { | |
| const contractId = req.params[contractIdParam] | |
| const userId = req.user?.id | |
| const role = req.user?.role as Role | |
| if (role === Role.ADMIN && hasPermission(role, Permission.OVERSEE_CONTRACTS)) { | |
| return next() | |
| } | |
| // Fetch contract and verify ownership | |
| try { | |
| const contract = await fetchContract(contractId) | |
| if (!contract) return res.status(404).json({ error: 'Contract not found' }) | |
| const hasAccess = | |
| (role === Role.VENDOR && contract.vendorId === userId) || | |
| (role === Role.CLIENT && contract.clientId === userId) | |
| if (!hasAccess) return res.status(403).json({ error: 'Access denied' }) | |
| next() | |
| } catch (err) { | |
| return res.status(500).json({ error: 'Internal error' }) | |
| } | |
| } | |
| } | |
| async function fetchContract(id: string) { | |
| // Replace with actual DB call | |
| return { id, vendorId: '', clientId: '' } | |
| } | |
| // ββ Impersonation (admin-only) ββ | |
| // Admins can impersonate with TTL-bound sessions and audit reason field | |
| export async function impersonateUser(adminId: string, targetUserId: string, reason: string, ttlMinutes: number = 30) { | |
| // 1. Verify admin has IMPERSONATE_USERS permission | |
| // 2. Create session with role=targetUser.role, token expires in ttlMinutes | |
| // 3. Log to AdminAuditLog: | |
| // { adminId, action: 'impersonate_start', target: targetUserId, detail: reason, ttl: ttlMinutes } | |
| // 4. Return impersonation session token | |
| } | |
| // ββ Rate Limiting ββ | |
| // Keyed on IP + method + pathname, backed by Redis | |
| // Implementation: use rate-limiter-flexible with Redis store | |
| // export const rateLimiter = new RateLimiterRedis({...}) | |