/** * Admin Guard * * Restricts access to system-level admin operations. * System administrators are configured via the SYSTEM_ADMIN_IDS environment variable. * * Configuration: * SYSTEM_ADMIN_IDS=uuid1,uuid2,uuid3 (comma-separated list of user IDs) * * Note: Workspace ownership does NOT grant system admin access. These are separate concepts: * - Workspace owner: Can manage their workspace and its members * - System admin: Can perform system-level operations across all workspaces */ import { Injectable, CanActivate, ExecutionContext, ForbiddenException, Logger, } from "@nestjs/common"; import type { AuthenticatedRequest } from "../../common/types/user.types"; @Injectable() export class AdminGuard implements CanActivate { private readonly logger = new Logger(AdminGuard.name); private readonly systemAdminIds: Set; constructor() { // Load system admin IDs from environment variable const adminIdsEnv = process.env.SYSTEM_ADMIN_IDS ?? ""; this.systemAdminIds = new Set( adminIdsEnv .split(",") .map((id) => id.trim()) .filter((id) => id.length > 0) ); if (this.systemAdminIds.size === 0) { this.logger.warn( "No system administrators configured. Set SYSTEM_ADMIN_IDS environment variable." ); } else { this.logger.log( `System administrators configured: ${String(this.systemAdminIds.size)} user(s)` ); } } /** * Check if a user ID is a system administrator */ isSystemAdmin(userId: string): boolean { return this.systemAdminIds.has(userId); } canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest(); const user = request.user; if (!user) { throw new ForbiddenException("User not authenticated"); } if (!this.isSystemAdmin(user.id)) { this.logger.warn(`Non-admin user ${user.id} attempted admin operation`); throw new ForbiddenException("This operation requires system administrator privileges"); } return true; } }