Matrix: avoid alias trust in group context

This commit is contained in:
Gustavo Madeira Santana 2026-03-12 08:51:26 +00:00
parent c9632f7ca6
commit 8a9d307177
No known key found for this signature in database
2 changed files with 58 additions and 6 deletions

View File

@ -256,6 +256,7 @@ describe("matrix monitor handler pairing account scope", () => {
it("skips media downloads for unmentioned group media messages", async () => {
const downloadContent = vi.fn(async () => Buffer.from("image"));
const getMemberDisplayName = vi.fn(async () => "sender");
const getRoomInfo = vi.fn(async () => ({ altAliases: [] }));
const { handler, resolveAgentRoute } = createMatrixHandlerTestHarness({
client: {
downloadContent,
@ -263,6 +264,7 @@ describe("matrix monitor handler pairing account scope", () => {
isDirectMessage: false,
mentionRegexes: [/@bot/i],
getMemberDisplayName,
getRoomInfo,
});
await handler("!room:example.org", {
@ -283,6 +285,7 @@ describe("matrix monitor handler pairing account scope", () => {
expect(downloadContent).not.toHaveBeenCalled();
expect(getMemberDisplayName).not.toHaveBeenCalled();
expect(getRoomInfo).not.toHaveBeenCalled();
expect(resolveAgentRoute).not.toHaveBeenCalled();
});
@ -307,6 +310,7 @@ describe("matrix monitor handler pairing account scope", () => {
prevBatch: null,
}));
const getMemberDisplayName = vi.fn(async () => "sender");
const getRoomInfo = vi.fn(async () => ({ altAliases: [] }));
const { handler, resolveAgentRoute } = createMatrixHandlerTestHarness({
client: {
getEvent,
@ -315,6 +319,7 @@ describe("matrix monitor handler pairing account scope", () => {
isDirectMessage: false,
mentionRegexes: [/@bot/i],
getMemberDisplayName,
getRoomInfo,
});
await handler("!room:example.org", {
@ -336,6 +341,7 @@ describe("matrix monitor handler pairing account scope", () => {
expect(getEvent).not.toHaveBeenCalled();
expect(getRelations).not.toHaveBeenCalled();
expect(getMemberDisplayName).not.toHaveBeenCalled();
expect(getRoomInfo).not.toHaveBeenCalled();
expect(resolveAgentRoute).not.toHaveBeenCalled();
});
@ -382,6 +388,38 @@ describe("matrix monitor handler pairing account scope", () => {
);
});
it("uses stable room ids instead of room-declared aliases in group context", async () => {
const { handler, finalizeInboundContext } = createMatrixHandlerTestHarness({
isDirectMessage: false,
getRoomInfo: async () => ({
name: "Ops Room",
canonicalAlias: "#spoofed:example.org",
altAliases: ["#alt:example.org"],
}),
getMemberDisplayName: async () => "sender",
dispatchReplyFromConfig: async () => ({
queuedFinal: false,
counts: { final: 0, block: 0, tool: 0 },
}),
});
await handler(
"!room:example.org",
createMatrixTextMessageEvent({
eventId: "$group1",
body: "@room hello",
mentions: { room: true },
}),
);
expect(finalizeInboundContext).toHaveBeenCalledWith(
expect.objectContaining({
GroupSubject: "Ops Room",
GroupChannel: "!room:example.org",
}),
);
});
it("routes bound Matrix threads to the target session key", async () => {
registerSessionBindingAdapter({
channel: "matrix",

View File

@ -225,10 +225,6 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
return;
}
const roomInfo = await getRoomInfo(roomId);
const roomName = roomInfo.name;
const roomAliases = [roomInfo.canonicalAlias ?? "", ...roomInfo.altAliases].filter(Boolean);
let content = event.content as RoomMessageEventContent;
if (
@ -260,16 +256,32 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
selfUserId,
});
const isRoom = !isDirectMessage;
let roomInfoPromise: Promise<{
name?: string;
canonicalAlias?: string;
altAliases: string[];
}> | null = null;
const getResolvedRoomInfo = async () => {
roomInfoPromise ??= getRoomInfo(roomId);
return await roomInfoPromise;
};
if (isRoom && groupPolicy === "disabled") {
return;
}
const roomInfoForConfig =
isRoom && roomsConfig && Object.keys(roomsConfig).some((key) => key.trim().startsWith("#"))
? await getResolvedRoomInfo()
: undefined;
const roomAliasesForConfig = roomInfoForConfig
? [roomInfoForConfig.canonicalAlias ?? "", ...roomInfoForConfig.altAliases].filter(Boolean)
: [];
const roomConfigInfo = isRoom
? resolveMatrixRoomConfig({
rooms: roomsConfig,
roomId,
aliases: roomAliases,
aliases: roomAliasesForConfig,
})
: undefined;
const roomConfig = roomConfigInfo?.config;
@ -548,6 +560,8 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
return;
}
const senderName = await getSenderName();
const roomInfo = isRoom ? await getResolvedRoomInfo() : undefined;
const roomName = roomInfo?.name;
const messageId = event.event_id ?? "";
const replyToEventId = content["m.relates_to"]?.["m.in_reply_to"]?.event_id;
@ -622,7 +636,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
SenderId: senderId,
SenderUsername: senderId.split(":")[0]?.replace(/^@/, ""),
GroupSubject: isRoom ? (roomName ?? roomId) : undefined,
GroupChannel: isRoom ? (roomInfo.canonicalAlias ?? roomId) : undefined,
GroupChannel: isRoom ? roomId : undefined,
GroupSystemPrompt: isRoom ? groupSystemPrompt : undefined,
Provider: "matrix" as const,
Surface: "matrix" as const,