fix: harden discord and slack reaction ingress authorization

This commit is contained in:
Peter Steinberger
2026-02-26 01:26:37 +01:00
parent c736f11a16
commit aedf62ac7e
8 changed files with 483 additions and 5 deletions

View File

@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
resolveDmAllowState,
resolveDmGroupAccessDecision,
resolveDmGroupAccessWithLists,
resolveEffectiveAllowFromLists,
} from "./dm-policy-shared.js";
@@ -75,6 +76,37 @@ describe("security/dm-policy-shared", () => {
expect(lists.effectiveGroupAllowFrom).toEqual(["+1111", "+2222"]);
});
it("resolves access + effective allowlists in one shared call", () => {
const resolved = resolveDmGroupAccessWithLists({
isGroup: false,
dmPolicy: "pairing",
groupPolicy: "allowlist",
allowFrom: ["owner"],
groupAllowFrom: ["group:room"],
storeAllowFrom: ["paired-user"],
isSenderAllowed: (allowFrom) => allowFrom.includes("paired-user"),
});
expect(resolved.decision).toBe("allow");
expect(resolved.reason).toBe("dmPolicy=pairing (allowlisted)");
expect(resolved.effectiveAllowFrom).toEqual(["owner", "paired-user"]);
expect(resolved.effectiveGroupAllowFrom).toEqual(["group:room", "paired-user"]);
});
it("keeps allowlist mode strict in shared resolver (no pairing-store fallback)", () => {
const resolved = resolveDmGroupAccessWithLists({
isGroup: false,
dmPolicy: "allowlist",
groupPolicy: "allowlist",
allowFrom: ["owner"],
groupAllowFrom: [],
storeAllowFrom: ["paired-user"],
isSenderAllowed: () => false,
});
expect(resolved.decision).toBe("block");
expect(resolved.reason).toBe("dmPolicy=allowlist (not allowlisted)");
expect(resolved.effectiveAllowFrom).toEqual(["owner"]);
});
const channels = [
"bluebubbles",
"imessage",

View File

@@ -77,6 +77,41 @@ export function resolveDmGroupAccessDecision(params: {
return { decision: "block", reason: `dmPolicy=${dmPolicy} (not allowlisted)` };
}
export function resolveDmGroupAccessWithLists(params: {
isGroup: boolean;
dmPolicy?: string | null;
groupPolicy?: string | null;
allowFrom?: Array<string | number> | null;
groupAllowFrom?: Array<string | number> | null;
storeAllowFrom?: Array<string | number> | null;
isSenderAllowed: (allowFrom: string[]) => boolean;
}): {
decision: DmGroupAccessDecision;
reason: string;
effectiveAllowFrom: string[];
effectiveGroupAllowFrom: string[];
} {
const { effectiveAllowFrom, effectiveGroupAllowFrom } = resolveEffectiveAllowFromLists({
allowFrom: params.allowFrom,
groupAllowFrom: params.groupAllowFrom,
storeAllowFrom: params.storeAllowFrom,
dmPolicy: params.dmPolicy,
});
const access = resolveDmGroupAccessDecision({
isGroup: params.isGroup,
dmPolicy: params.dmPolicy,
groupPolicy: params.groupPolicy,
effectiveAllowFrom,
effectiveGroupAllowFrom,
isSenderAllowed: params.isSenderAllowed,
});
return {
...access,
effectiveAllowFrom,
effectiveGroupAllowFrom,
};
}
export async function resolveDmAllowState(params: {
provider: ChannelId;
allowFrom?: Array<string | number> | null;