using System.Security.Claims; using Data.SeaHavenIndustries; using SeaHaven.Services.Exceptions; namespace SeaHaven.Services.Helpers { /// /// Claims-derived authorization for work-order media read/mutations. /// Callers must already have resolved the work order via /// ApplyBaseScope (non-deleted, non-template). Staff may access any /// such work order; technicians only when /// matches the actor. This is not tenant/customer isolation — that /// hard rule remains open pending /// docs/adr/0001-work-order-single-org-scope.md (Proposed). /// public static class WorkOrderMediaAuthorization { private static readonly string[] StaffRoles = { "Admin", "Manager", "Dispatcher", "Supervisor" }; public static void EnsureCanRead(ClaimsPrincipal user, string? actorId) { EnsureAuthenticated(user, actorId, "You are not allowed to view work order media."); if (IsStaff(user) || user.IsInRole("User")) return; throw Forbidden("You are not allowed to view work order media."); } public static void EnsureCanMutate(ClaimsPrincipal user, string? actorId) { EnsureAuthenticated(user, actorId); if (IsStaff(user) || user.IsInRole("User")) return; throw Forbidden(); } public static void EnsureCanDelete(ClaimsPrincipal user, string? actorId) { EnsureAuthenticated(user, actorId); // Technician (User) may upload/categorize assigned media but not delete. if (IsStaff(user)) return; throw Forbidden(); } /// /// Caller-scope check after an ApplyBaseScope work-order load. /// Staff: any base-scoped work order (interim; no tenant key — ADR 0001 Proposed). /// Technician: only when assigned to the caller. /// Out of caller scope → NotFound (no disclosure). /// public static void EnsureWorkOrderInCallerScope( ClaimsPrincipal user, string actorId, WorkOrder workOrder) { // ApplyBaseScope already filtered the load. Staff may reach any such // work order (board-aligned interim). Not a tenant boundary — see // ADR 0001 (Proposed). if (IsStaff(user)) return; if (user.IsInRole("User") && string.Equals(workOrder.AssignTo, actorId, StringComparison.Ordinal)) { return; } throw new WorkOrderBoardValidationException("NotFound", "Work order not found."); } private static void EnsureAuthenticated( ClaimsPrincipal user, string? actorId, string? forbiddenMessage = null) { if (user is null || !(user.Identity?.IsAuthenticated ?? false) || string.IsNullOrWhiteSpace(actorId)) { throw Forbidden(forbiddenMessage); } } private static bool IsStaff(ClaimsPrincipal user) => StaffRoles.Any(user.IsInRole); private static WorkOrderBoardValidationException Forbidden(string? message = null) => new( "Forbidden", message ?? "You are not allowed to mutate work order media."); } }