diff --git a/extensions/matrix/src/matrix/monitor/index.access-config.test.ts b/extensions/matrix/src/matrix/monitor/index.access-config.test.ts new file mode 100644 index 000000000000..ec2c71c6de41 --- /dev/null +++ b/extensions/matrix/src/matrix/monitor/index.access-config.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from "vitest"; +import type { MatrixConfig } from "../../types.js"; +import { resolveMatrixDmAccessConfig } from "./index.js"; + +describe("resolveMatrixDmAccessConfig", () => { + it("supports legacy dmPolicy + allowFrom fields", () => { + const cfg = { + dmPolicy: "allowlist", + allowFrom: ["@alice:example.org"], + } as unknown as MatrixConfig; + + const resolved = resolveMatrixDmAccessConfig(cfg); + + expect(resolved.dmPolicyRaw).toBe("allowlist"); + expect(resolved.allowFrom).toEqual(["@alice:example.org"]); + expect(resolved.groupAllowFrom).toEqual(["@alice:example.org"]); + }); + + it("falls back group allowlist to dm allowlist when groupAllowFrom is unset", () => { + const cfg = { + dm: { policy: "allowlist", allowFrom: ["@bob:example.org"] }, + } as MatrixConfig; + + const resolved = resolveMatrixDmAccessConfig(cfg); + + expect(resolved.allowFrom).toEqual(["@bob:example.org"]); + expect(resolved.groupAllowFrom).toEqual(["@bob:example.org"]); + }); + + it("keeps explicit groupAllowFrom when provided", () => { + const cfg = { + dm: { policy: "allowlist", allowFrom: ["@bob:example.org"] }, + groupAllowFrom: ["@carol:example.org"], + } as MatrixConfig; + + const resolved = resolveMatrixDmAccessConfig(cfg); + + expect(resolved.allowFrom).toEqual(["@bob:example.org"]); + expect(resolved.groupAllowFrom).toEqual(["@carol:example.org"]); + }); +}); diff --git a/extensions/matrix/src/matrix/monitor/index.ts b/extensions/matrix/src/matrix/monitor/index.ts index 936eabdd3467..dd799313e041 100644 --- a/extensions/matrix/src/matrix/monitor/index.ts +++ b/extensions/matrix/src/matrix/monitor/index.ts @@ -36,6 +36,28 @@ export type MonitorMatrixOpts = { }; const DEFAULT_MEDIA_MAX_MB = 20; +const VALID_DM_POLICIES = new Set(["pairing", "allowlist", "open", "disabled"]); + +export function resolveMatrixDmAccessConfig(accountConfig: CoreConfig["channels"]["matrix"]) { + const legacyAllowFrom = ( + accountConfig as { + allowFrom?: Array; + } + ).allowFrom; + const allowFromBase = accountConfig.dm?.allowFrom ?? legacyAllowFrom ?? []; + const allowFrom = allowFromBase.map(String); + const groupAllowFrom = + accountConfig.groupAllowFrom && accountConfig.groupAllowFrom.length > 0 + ? accountConfig.groupAllowFrom.map(String) + : allowFrom; + const legacyDmPolicy = (accountConfig as { dmPolicy?: unknown }).dmPolicy; + const dmPolicyCandidate = accountConfig.dm?.policy ?? legacyDmPolicy; + const dmPolicyRaw = + typeof dmPolicyCandidate === "string" && VALID_DM_POLICIES.has(dmPolicyCandidate) + ? dmPolicyCandidate + : "pairing"; + return { allowFrom, groupAllowFrom, dmPolicyRaw }; +} export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promise { if (isBunRuntime()) { @@ -128,8 +150,9 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi const accountConfig = account.config; const allowlistOnly = accountConfig.allowlistOnly === true; - let allowFrom: string[] = (accountConfig.dm?.allowFrom ?? []).map(String); - let groupAllowFrom: string[] = (accountConfig.groupAllowFrom ?? []).map(String); + const accessConfig = resolveMatrixDmAccessConfig(accountConfig); + let allowFrom: string[] = accessConfig.allowFrom; + let groupAllowFrom: string[] = accessConfig.groupAllowFrom; let roomsConfig = accountConfig.groups ?? accountConfig.rooms; allowFrom = await resolveUserAllowlist("matrix dm allowlist", allowFrom); @@ -262,7 +285,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi const threadReplies = accountConfig.threadReplies ?? "inbound"; const dmConfig = accountConfig.dm; const dmEnabled = dmConfig?.enabled ?? true; - const dmPolicyRaw = dmConfig?.policy ?? "pairing"; + const dmPolicyRaw = accessConfig.dmPolicyRaw; const dmPolicy = allowlistOnly && dmPolicyRaw !== "disabled" ? "allowlist" : dmPolicyRaw; const textLimit = core.channel.text.resolveTextChunkLimit(cfg, "matrix"); const mediaMaxMb = opts.mediaMaxMb ?? accountConfig.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;