refactor(bluebubbles): share dm/group access policy checks

This commit is contained in:
Peter Steinberger
2026-02-21 20:08:17 +01:00
parent c3af00bddb
commit 4540790cb6
4 changed files with 265 additions and 126 deletions

View File

@@ -1,5 +1,9 @@
import { describe, expect, it } from "vitest";
import { resolveDmAllowState } from "./dm-policy-shared.js";
import {
resolveDmAllowState,
resolveDmGroupAccessDecision,
resolveEffectiveAllowFromLists,
} from "./dm-policy-shared.js";
describe("security/dm-policy-shared", () => {
it("normalizes config + store allow entries and counts distinct senders", async () => {
@@ -28,4 +32,94 @@ describe("security/dm-policy-shared", () => {
expect(state.allowCount).toBe(0);
expect(state.isMultiUserDm).toBe(false);
});
it("builds effective DM/group allowlists from config + pairing store", () => {
const lists = resolveEffectiveAllowFromLists({
allowFrom: [" owner ", "", "owner2"],
groupAllowFrom: ["group:abc"],
storeAllowFrom: [" owner3 ", ""],
});
expect(lists.effectiveAllowFrom).toEqual(["owner", "owner2", "owner3"]);
expect(lists.effectiveGroupAllowFrom).toEqual(["group:abc", "owner3"]);
});
it("falls back to DM allowlist for groups when groupAllowFrom is empty", () => {
const lists = resolveEffectiveAllowFromLists({
allowFrom: [" owner "],
groupAllowFrom: [],
storeAllowFrom: [" owner2 "],
});
expect(lists.effectiveAllowFrom).toEqual(["owner", "owner2"]);
expect(lists.effectiveGroupAllowFrom).toEqual(["owner", "owner2"]);
});
const channels = [
"bluebubbles",
"imessage",
"signal",
"telegram",
"whatsapp",
"msteams",
"matrix",
"zalo",
] as const;
for (const channel of channels) {
it(`[${channel}] blocks DM allowlist mode when allowlist is empty`, () => {
const decision = resolveDmGroupAccessDecision({
isGroup: false,
dmPolicy: "allowlist",
groupPolicy: "allowlist",
effectiveAllowFrom: [],
effectiveGroupAllowFrom: [],
isSenderAllowed: () => false,
});
expect(decision).toEqual({
decision: "block",
reason: "dmPolicy=allowlist (not allowlisted)",
});
});
it(`[${channel}] uses pairing flow when DM sender is not allowlisted`, () => {
const decision = resolveDmGroupAccessDecision({
isGroup: false,
dmPolicy: "pairing",
groupPolicy: "allowlist",
effectiveAllowFrom: [],
effectiveGroupAllowFrom: [],
isSenderAllowed: () => false,
});
expect(decision).toEqual({
decision: "pairing",
reason: "dmPolicy=pairing (not allowlisted)",
});
});
it(`[${channel}] allows DM sender when allowlisted`, () => {
const decision = resolveDmGroupAccessDecision({
isGroup: false,
dmPolicy: "allowlist",
groupPolicy: "allowlist",
effectiveAllowFrom: ["owner"],
effectiveGroupAllowFrom: [],
isSenderAllowed: () => true,
});
expect(decision.decision).toBe("allow");
});
it(`[${channel}] blocks group allowlist mode when sender/group is not allowlisted`, () => {
const decision = resolveDmGroupAccessDecision({
isGroup: true,
dmPolicy: "pairing",
groupPolicy: "allowlist",
effectiveAllowFrom: ["owner"],
effectiveGroupAllowFrom: ["group:abc"],
isSenderAllowed: () => false,
});
expect(decision).toEqual({
decision: "block",
reason: "groupPolicy=allowlist (not allowlisted)",
});
});
}
});