fix(matrix): keep DM allowlist out of room commands

This commit is contained in:
Peter Steinberger
2026-04-23 07:09:34 +01:00
parent 912dcfbc2b
commit c23ad91a14
3 changed files with 59 additions and 2 deletions

View File

@@ -22,7 +22,7 @@ describe("resolveMatrixMonitorAccessState", () => {
expect(state.roomUserMatch?.allowed).toBe(true);
expect(state.groupAllowMatch?.allowed).toBe(false);
expect(state.commandAuthorizers).toEqual([
{ configured: true, allowed: false },
{ configured: false, allowed: false },
{ configured: true, allowed: true },
{ configured: true, allowed: false },
]);
@@ -47,6 +47,24 @@ describe("resolveMatrixMonitorAccessState", () => {
]);
});
it("does not let configured DM allowFrom authorize room control commands", () => {
const state = resolveMatrixMonitorAccessState({
allowFrom: ["@owner:example.org"],
storeAllowFrom: [],
groupAllowFrom: ["@admin:example.org"],
roomUsers: [],
senderId: "@owner:example.org",
isRoom: true,
});
expect(state.directAllowMatch.allowed).toBe(true);
expect(state.commandAuthorizers).toEqual([
{ configured: false, allowed: false },
{ configured: false, allowed: false },
{ configured: true, allowed: false },
]);
});
it("keeps room-user matching disabled for dm traffic", () => {
const state = resolveMatrixMonitorAccessState({
allowFrom: [],

View File

@@ -37,7 +37,7 @@ export function resolveMatrixMonitorAccessState(params: {
]);
const effectiveGroupAllowFrom = normalizeMatrixAllowList(params.groupAllowFrom);
const effectiveRoomUsers = normalizeMatrixAllowList(params.roomUsers);
const commandAllowFrom = params.isRoom ? configuredAllowFrom : effectiveAllowFrom;
const commandAllowFrom = params.isRoom ? [] : effectiveAllowFrom;
const directAllowMatch = resolveMatrixAllowListMatch({
allowList: effectiveAllowFrom,

View File

@@ -512,6 +512,45 @@ describe("matrix monitor handler pairing account scope", () => {
expect(readAllowFromStore).not.toHaveBeenCalled();
});
it("blocks room control commands from configured DM-only senders", async () => {
const hasControlCommand = vi.fn((text?: string) => text === "/new");
const { handler, finalizeInboundContext, recordInboundSession } =
createMatrixHandlerTestHarness({
isDirectMessage: false,
roomsConfig: {
"!room:example.org": { requireMention: false },
},
shouldHandleTextCommands: () => true,
hasControlCommand,
cfg: {
commands: {
useAccessGroups: true,
},
channels: {
matrix: {
dm: { allowFrom: ["@observer:example.org"] },
groupAllowFrom: ["@driver:example.org"],
},
},
},
groupPolicy: "open",
getMemberDisplayName: async () => "observer",
});
await handler(
"!room:example.org",
createMatrixTextMessageEvent({
eventId: "$dm-configured-room-command",
sender: "@observer:example.org",
body: "@bot:example.org /new",
}),
);
expect(hasControlCommand).toHaveBeenCalledWith("/new", expect.anything());
expect(recordInboundSession).not.toHaveBeenCalled();
expect(finalizeInboundContext).not.toHaveBeenCalled();
});
it("strips the Matrix self user id before room slash command detection", async () => {
const hasControlCommand = vi.fn((text?: string) => text === "/new");
const { handler, finalizeInboundContext, recordInboundSession } =