mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix(session): tighten direct-session webchat routing matching (#37867)
* fix(session): require strict direct key routing shapes * test(session): cover direct route poisoning cases
This commit is contained in:
56
src/auto-reply/reply/session-delivery.test.ts
Normal file
56
src/auto-reply/reply/session-delivery.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveLastChannelRaw, resolveLastToRaw } from "./session-delivery.js";
|
||||
|
||||
describe("session delivery direct-session routing overrides", () => {
|
||||
it.each([
|
||||
"agent:main:direct:user-1",
|
||||
"agent:main:telegram:direct:123456",
|
||||
"agent:main:telegram:account-a:direct:123456",
|
||||
"agent:main:telegram:dm:123456",
|
||||
"agent:main:telegram:direct:123456:thread:99",
|
||||
"agent:main:telegram:account-a:direct:123456:topic:ops",
|
||||
])("lets webchat override persisted routes for strict direct key %s", (sessionKey) => {
|
||||
expect(
|
||||
resolveLastChannelRaw({
|
||||
originatingChannelRaw: "webchat",
|
||||
persistedLastChannel: "telegram",
|
||||
sessionKey,
|
||||
}),
|
||||
).toBe("webchat");
|
||||
expect(
|
||||
resolveLastToRaw({
|
||||
originatingChannelRaw: "webchat",
|
||||
originatingToRaw: "session:dashboard",
|
||||
persistedLastChannel: "telegram",
|
||||
persistedLastTo: "123456",
|
||||
sessionKey,
|
||||
}),
|
||||
).toBe("session:dashboard");
|
||||
});
|
||||
|
||||
it.each([
|
||||
"agent:main:main:direct",
|
||||
"agent:main:cron:job-1:dm",
|
||||
"agent:main:subagent:worker:direct:user-1",
|
||||
"agent:main:telegram:channel:direct",
|
||||
"agent:main:telegram:account-a:direct",
|
||||
"agent:main:telegram:direct:123456:cron:job-1",
|
||||
])("keeps persisted external routes for malformed direct-like key %s", (sessionKey) => {
|
||||
expect(
|
||||
resolveLastChannelRaw({
|
||||
originatingChannelRaw: "webchat",
|
||||
persistedLastChannel: "telegram",
|
||||
sessionKey,
|
||||
}),
|
||||
).toBe("telegram");
|
||||
expect(
|
||||
resolveLastToRaw({
|
||||
originatingChannelRaw: "webchat",
|
||||
originatingToRaw: "session:dashboard",
|
||||
persistedLastChannel: "telegram",
|
||||
persistedLastTo: "group:12345",
|
||||
sessionKey,
|
||||
}),
|
||||
).toBe("group:12345");
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { buildAgentMainSessionKey } from "../../routing/session-key.js";
|
||||
import { deriveSessionChatType, parseAgentSessionKey } from "../../sessions/session-key-utils.js";
|
||||
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
|
||||
import {
|
||||
deliveryContextFromSession,
|
||||
deliveryContextKey,
|
||||
@@ -38,8 +38,44 @@ function isMainSessionKey(sessionKey?: string): boolean {
|
||||
return parsed.rest.trim().toLowerCase() === "main";
|
||||
}
|
||||
|
||||
const DIRECT_SESSION_MARKERS = new Set(["direct", "dm"]);
|
||||
const THREAD_SESSION_MARKERS = new Set(["thread", "topic"]);
|
||||
|
||||
function hasStrictDirectSessionTail(parts: string[], markerIndex: number): boolean {
|
||||
const peerId = parts[markerIndex + 1]?.trim();
|
||||
if (!peerId) {
|
||||
return false;
|
||||
}
|
||||
const tail = parts.slice(markerIndex + 2);
|
||||
if (tail.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return tail.length === 2 && THREAD_SESSION_MARKERS.has(tail[0] ?? "") && Boolean(tail[1]?.trim());
|
||||
}
|
||||
|
||||
function isDirectSessionKey(sessionKey?: string): boolean {
|
||||
return deriveSessionChatType(sessionKey) === "direct";
|
||||
const raw = (sessionKey ?? "").trim().toLowerCase();
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
const scoped = parseAgentSessionKey(raw)?.rest ?? raw;
|
||||
const parts = scoped.split(":").filter(Boolean);
|
||||
if (parts.length < 2) {
|
||||
return false;
|
||||
}
|
||||
if (DIRECT_SESSION_MARKERS.has(parts[0] ?? "")) {
|
||||
return hasStrictDirectSessionTail(parts, 0);
|
||||
}
|
||||
const channel = normalizeMessageChannel(parts[0]);
|
||||
if (!channel || !isDeliverableMessageChannel(channel)) {
|
||||
return false;
|
||||
}
|
||||
if (DIRECT_SESSION_MARKERS.has(parts[1] ?? "")) {
|
||||
return hasStrictDirectSessionTail(parts, 1);
|
||||
}
|
||||
return Boolean(parts[1]?.trim()) && DIRECT_SESSION_MARKERS.has(parts[2] ?? "")
|
||||
? hasStrictDirectSessionTail(parts, 2)
|
||||
: false;
|
||||
}
|
||||
|
||||
function isExternalRoutingChannel(channel?: string): channel is string {
|
||||
|
||||
Reference in New Issue
Block a user