diff --git a/src/lib/perms/can.ts b/src/lib/perms/can.ts index 6db7f23..04778cf 100644 --- a/src/lib/perms/can.ts +++ b/src/lib/perms/can.ts @@ -1,30 +1,77 @@ import type { Role } from "@prisma/client"; import { minimatch } from "minimatch"; -export function can( +export interface PermissionTrace { roles: Role[], targetVacc: string | null, userVacc: string | null, req_perm: string, -): boolean { + all_permissions: string[] + outcome: boolean, + because: string, + checked_perms: { original: string, replaced: string, was_replaced: boolean, req_perm: string, matched: boolean }[] +} + +export function _can(roles: Role[], targetVacc: string | null, userVacc: string | null, req_perm: string): [boolean, PermissionTrace] { + let trace: PermissionTrace = { + roles, + targetVacc, + userVacc, + req_perm, + all_permissions: [], + outcome: false, + because: "not yet evaluated", + checked_perms: [] + }; + if (roles === null || roles === undefined) { - return false; + trace.outcome = false; + trace.because = "roles is null or undefined"; + return [false, trace]; } + let all_perms: string[] = []; + + trace.all_permissions = all_perms; + for (let role of roles) { all_perms = all_perms.concat(role.permissions); } + for (let perm of all_perms) { + let traceperm = { + original: perm, + replaced: "", + req_perm, + matched: false, + was_replaced: false + } let real_perm = perm; if (targetVacc == userVacc) { + traceperm.was_replaced = true; real_perm = perm.replace("vacc.own", `vacc.${targetVacc}`); } + traceperm.replaced = real_perm; if (minimatch(req_perm, real_perm)) { - return true; + traceperm.matched = true; + trace.checked_perms.push(traceperm); + return [true, trace]; } + traceperm.matched = false; + trace.checked_perms.push(traceperm); } - return false; + trace.because = "no permissions matched"; + return [false, trace]; +} + +export function can( + roles: Role[], + targetVacc: string | null, + userVacc: string | null, + req_perm: string, +): boolean { + return _can(roles, targetVacc, userVacc, req_perm)[0]; } export function canAny( diff --git a/src/routes/api/v1/permissions_debug/[user]/can/[permission]/in/[vacc]/+server.ts b/src/routes/api/v1/permissions_debug/[user]/can/[permission]/in/[vacc]/+server.ts new file mode 100644 index 0000000..f597176 --- /dev/null +++ b/src/routes/api/v1/permissions_debug/[user]/can/[permission]/in/[vacc]/+server.ts @@ -0,0 +1,28 @@ + +import prisma from "$lib/prisma"; +import {_can} from "$lib/perms/can"; +import {getUserRoles} from "$lib/perms/getUserRoles"; + +export async function GET({ params }) { + let user = await prisma.user.findUnique({ + where: { + id: params.user + } + }); + if (user === null) { + return new Response(JSON.stringify({ + success: false, + because: "user does not exist" + })); + } + let user_roles = await getUserRoles(user.id)!; + + let [canPerform, permTrace] = _can(user_roles!, params.vacc, user.vaccId, params.permission); + + return new Response(JSON.stringify({ + success: true, + can: canPerform, + because: permTrace, + user: user + })); +}