Files
OwnCord/Client/tauri-client/tests/unit/permissions.test.ts
T
jevb 867041b094 test: client test updates — fix failures + align with security hardening
Update 111 test files to match security hardening changes:
- acceptInvalidCerts now conditional on allowSelfSigned
- Credential store no longer returns passwords over IPC
- File type validation uses strict MIME allowlist
- Search rate limiter timing adjustments
- Dispatcher cleanup mock additions
- Audio elements screenshare mute preservation

2962 tests passing across 110 test files.
2026-04-01 11:40:31 +02:00

215 lines
7.2 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
hasPermission,
hasAnyPermission,
hasAllPermissions,
computeEffective,
isAdministrator,
} from "../../src/lib/permissions";
import { Permission } from "../../src/lib/types";
// Default role permission values (from SCHEMA.md)
const OWNER_PERMS = 0x7fffffff;
const ADMIN_PERMS = 0x3fffffff; // admin has bits 0-29 but NOT ADMINISTRATOR (bit 30)
const MODERATOR_PERMS = 0x000fffff;
const MEMBER_PERMS = 0x00000663;
describe("hasPermission", () => {
it("member can SEND_MESSAGES", () => {
expect(hasPermission(MEMBER_PERMS, Permission.SEND_MESSAGES)).toBe(true);
});
it("member cannot MANAGE_MESSAGES", () => {
expect(hasPermission(MEMBER_PERMS, Permission.MANAGE_MESSAGES)).toBe(false);
});
it("ADMINISTRATOR bypass — admin with ADMINISTRATOR can do anything", () => {
const permsWithAdmin = Permission.ADMINISTRATOR;
expect(hasPermission(permsWithAdmin, Permission.MANAGE_MESSAGES)).toBe(true);
expect(hasPermission(permsWithAdmin, Permission.BAN_MEMBERS)).toBe(true);
});
it("owner has all permissions", () => {
expect(hasPermission(OWNER_PERMS, Permission.SEND_MESSAGES)).toBe(true);
expect(hasPermission(OWNER_PERMS, Permission.MANAGE_SERVER)).toBe(true);
expect(hasPermission(OWNER_PERMS, Permission.VIEW_AUDIT_LOG)).toBe(true);
expect(hasPermission(OWNER_PERMS, Permission.ADMINISTRATOR)).toBe(true);
});
});
describe("hasAnyPermission", () => {
it("returns true if any match", () => {
expect(
hasAnyPermission(MEMBER_PERMS, Permission.SEND_MESSAGES, Permission.MANAGE_MESSAGES),
).toBe(true);
});
it("returns false if none match", () => {
expect(hasAnyPermission(MEMBER_PERMS, Permission.MANAGE_MESSAGES, Permission.BAN_MEMBERS)).toBe(
false,
);
});
it("ADMINISTRATOR bypass — always returns true", () => {
expect(
hasAnyPermission(
Permission.ADMINISTRATOR,
Permission.MANAGE_MESSAGES,
Permission.BAN_MEMBERS,
),
).toBe(true);
});
it("returns true when only one of many perms matches", () => {
expect(
hasAnyPermission(
MEMBER_PERMS,
Permission.BAN_MEMBERS,
Permission.MANAGE_SERVER,
Permission.READ_MESSAGES,
),
).toBe(true);
});
it("returns false with zero permissions", () => {
expect(hasAnyPermission(0, Permission.SEND_MESSAGES, Permission.READ_MESSAGES)).toBe(false);
});
});
describe("hasAllPermissions", () => {
it("returns true when all match", () => {
expect(
hasAllPermissions(MEMBER_PERMS, Permission.SEND_MESSAGES, Permission.READ_MESSAGES),
).toBe(true);
});
it("returns false when one missing", () => {
expect(
hasAllPermissions(MEMBER_PERMS, Permission.SEND_MESSAGES, Permission.MANAGE_MESSAGES),
).toBe(false);
});
it("ADMINISTRATOR bypass — always returns true", () => {
expect(
hasAllPermissions(
Permission.ADMINISTRATOR,
Permission.MANAGE_MESSAGES,
Permission.BAN_MEMBERS,
Permission.MANAGE_SERVER,
),
).toBe(true);
});
it("returns false when zero perms and checking multiple", () => {
expect(hasAllPermissions(0, Permission.SEND_MESSAGES, Permission.READ_MESSAGES)).toBe(false);
});
it("returns true with no permissions to check (vacuous truth)", () => {
expect(hasAllPermissions(MEMBER_PERMS)).toBe(true);
});
});
describe("computeEffective", () => {
it("allow overrides deny (allow-wins, matches server semantics)", () => {
const base = MEMBER_PERMS;
const allow = Permission.MANAGE_MESSAGES;
const deny = Permission.MANAGE_MESSAGES;
const effective = computeEffective(base, allow, deny);
expect(effective & Permission.MANAGE_MESSAGES).toBe(Permission.MANAGE_MESSAGES);
});
it("ADMINISTRATOR ignores deny and returns all bits", () => {
// Must use a perm set that actually includes bit 30 (ADMINISTRATOR)
const base = OWNER_PERMS; // 0x7FFFFFFF includes ADMINISTRATOR
const deny = Permission.SEND_MESSAGES | Permission.MANAGE_SERVER;
const effective = computeEffective(base, 0, deny);
expect(effective).toBe(0x7fffffff);
});
it("non-ADMINISTRATOR admin is affected by deny", () => {
// ADMIN_PERMS (0x3FFFFFFF) does NOT have ADMINISTRATOR bit
const deny = Permission.SEND_MESSAGES;
const effective = computeEffective(ADMIN_PERMS, 0, deny);
expect(effective & Permission.SEND_MESSAGES).toBe(0);
});
it("allow adds bits to base", () => {
const base = MEMBER_PERMS;
const allow = Permission.MANAGE_MESSAGES;
const effective = computeEffective(base, allow, 0);
expect(effective & Permission.MANAGE_MESSAGES).toBe(Permission.MANAGE_MESSAGES);
// original bits are preserved
expect(effective & Permission.SEND_MESSAGES).toBe(Permission.SEND_MESSAGES);
});
});
describe("isAdministrator", () => {
it("true for owner with ADMINISTRATOR bit", () => {
expect(isAdministrator(OWNER_PERMS)).toBe(true);
});
it("false for admin without ADMINISTRATOR bit", () => {
// ADMIN_PERMS (0x3FFFFFFF) has bits 0-29 but NOT bit 30
expect(isAdministrator(ADMIN_PERMS)).toBe(false);
});
it("false for member", () => {
expect(isAdministrator(MEMBER_PERMS)).toBe(false);
});
it("false for zero permissions", () => {
expect(isAdministrator(0)).toBe(false);
});
it("true for exactly ADMINISTRATOR bit only", () => {
expect(isAdministrator(Permission.ADMINISTRATOR)).toBe(true);
});
});
describe("edge cases", () => {
it("hasPermission with zero perms returns false", () => {
expect(hasPermission(0, Permission.SEND_MESSAGES)).toBe(false);
});
it("hasPermission checking ADMINISTRATOR bit directly", () => {
expect(hasPermission(Permission.ADMINISTRATOR, Permission.ADMINISTRATOR)).toBe(true);
});
it("computeEffective with zero base, allow, deny", () => {
expect(computeEffective(0, 0, 0)).toBe(0);
});
it("computeEffective deny removes bits from base", () => {
const base = Permission.SEND_MESSAGES | Permission.READ_MESSAGES;
const deny = Permission.SEND_MESSAGES;
const effective = computeEffective(base, 0, deny);
expect(effective & Permission.SEND_MESSAGES).toBe(0);
expect(effective & Permission.READ_MESSAGES).toBe(Permission.READ_MESSAGES);
});
it("computeEffective with allow and deny for different bits", () => {
const base = Permission.SEND_MESSAGES;
const allow = Permission.MANAGE_MESSAGES;
const deny = Permission.SEND_MESSAGES;
const effective = computeEffective(base, allow, deny);
expect(effective & Permission.SEND_MESSAGES).toBe(0);
expect(effective & Permission.MANAGE_MESSAGES).toBe(Permission.MANAGE_MESSAGES);
});
it("hasAnyPermission with single matching perm", () => {
expect(hasAnyPermission(Permission.SEND_MESSAGES, Permission.SEND_MESSAGES)).toBe(true);
});
it("hasAllPermissions with single matching perm", () => {
expect(hasAllPermissions(Permission.SEND_MESSAGES, Permission.SEND_MESSAGES)).toBe(true);
});
it("moderator has KICK_MEMBERS", () => {
expect(hasPermission(MODERATOR_PERMS, Permission.KICK_MEMBERS)).toBe(true);
});
it("moderator does not have MANAGE_SERVER", () => {
expect(hasPermission(MODERATOR_PERMS, Permission.MANAGE_SERVER)).toBe(false);
});
});