Prechádzať zdrojové kódy

RHL-021 feat(rbac): implement branch access control logic and corresponding tests

Code_Uwe 1 mesiac pred
rodič
commit
a13b89052e

+ 48 - 0
lib/frontend/rbac/branchAccess.js

@@ -0,0 +1,48 @@
+/**
+ * UI-side RBAC decision helpers for branch-based routes (RHL-021).
+ *
+ * This module is pure (no React / no Next runtime).
+ * The UI can use it to decide whether a user may access a given `:branch` segment.
+ */
+
+/**
+ * @typedef {Object} AuthUser
+ * @property {string} userId
+ * @property {string} role
+ * @property {string|null} branchId
+ */
+
+export const BRANCH_ACCESS = Object.freeze({
+	ALLOWED: "allowed",
+	FORBIDDEN: "forbidden",
+});
+
+/**
+ * Decide whether the given user can access a route branch.
+ *
+ * Rules:
+ * - role "branch": only allowed when routeBranch === user.branchId
+ * - role "admin" / "dev": allowed for any route branch
+ * - unknown roles or missing required data: forbidden
+ *
+ * @param {AuthUser|null} user
+ * @param {string} routeBranch
+ * @returns {"allowed"|"forbidden"}
+ */
+export function getBranchAccess(user, routeBranch) {
+	if (!user || typeof routeBranch !== "string" || !routeBranch) {
+		return BRANCH_ACCESS.FORBIDDEN;
+	}
+
+	if (user.role === "branch") {
+		return user.branchId === routeBranch
+			? BRANCH_ACCESS.ALLOWED
+			: BRANCH_ACCESS.FORBIDDEN;
+	}
+
+	if (user.role === "admin" || user.role === "dev") {
+		return BRANCH_ACCESS.ALLOWED;
+	}
+
+	return BRANCH_ACCESS.FORBIDDEN;
+}

+ 34 - 0
lib/frontend/rbac/branchAccess.test.js

@@ -0,0 +1,34 @@
+/* @vitest-environment node */
+
+import { describe, it, expect } from "vitest";
+import { getBranchAccess, BRANCH_ACCESS } from "./branchAccess.js";
+
+describe("lib/frontend/rbac/branchAccess", () => {
+	it("allows branch users only for their own branch", () => {
+		const user = { userId: "u1", role: "branch", branchId: "NL01" };
+
+		expect(getBranchAccess(user, "NL01")).toBe(BRANCH_ACCESS.ALLOWED);
+		expect(getBranchAccess(user, "NL02")).toBe(BRANCH_ACCESS.FORBIDDEN);
+	});
+
+	it("allows admin/dev users for any branch", () => {
+		const admin = { userId: "u2", role: "admin", branchId: null };
+		const dev = { userId: "u3", role: "dev", branchId: null };
+
+		expect(getBranchAccess(admin, "NL01")).toBe(BRANCH_ACCESS.ALLOWED);
+		expect(getBranchAccess(admin, "NL99")).toBe(BRANCH_ACCESS.ALLOWED);
+
+		expect(getBranchAccess(dev, "NL01")).toBe(BRANCH_ACCESS.ALLOWED);
+		expect(getBranchAccess(dev, "NL99")).toBe(BRANCH_ACCESS.ALLOWED);
+	});
+
+	it("denies unknown roles and missing data", () => {
+		expect(getBranchAccess(null, "NL01")).toBe(BRANCH_ACCESS.FORBIDDEN);
+
+		const weird = { userId: "u9", role: "user", branchId: "NL01" };
+		expect(getBranchAccess(weird, "NL01")).toBe(BRANCH_ACCESS.FORBIDDEN);
+
+		const branchNoId = { userId: "u1", role: "branch", branchId: null };
+		expect(getBranchAccess(branchNoId, "NL01")).toBe(BRANCH_ACCESS.FORBIDDEN);
+	});
+});