fix(discord): normalize command allowFrom prefixes
This commit is contained in:
@@ -46,6 +46,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Telegram: preserve private-chat topic `message_thread_id` on outbound sends (message/sticker/poll), keep thread-not-found retry fallback, and avoid masking `chat not found` routing errors. (#18993) Thanks @obviyus.
|
||||
- Discord: prevent duplicate media delivery when the model uses the `message send` tool with media, by skipping media extraction from messaging tool results since the tool already sent the message directly. (#18270)
|
||||
- Discord: route `audioAsVoice` auto-replies through the voice message API so opt-in audio renders as voice messages. (#18041) Thanks @zerone0x.
|
||||
- Discord/Commands: normalize `commands.allowFrom` entries with `user:`/`discord:`/`pk:` prefixes and `<@id>` mentions so command authorization matches Discord allowlist behavior. (#18042)
|
||||
- Telegram: keep draft-stream preview replies attached to the user message for `replyToMode: "all"` in groups and DMs, preserving threaded reply context from preview through finalization. (#17880) Thanks @yinghaosang.
|
||||
- Telegram: prevent streaming final replies from being overwritten by later final/error payloads, and suppress fallback tool-error warnings when a recovered assistant answer already exists after tool calls. (#17883) Thanks @Marvae and @obviyus.
|
||||
- Telegram: debounce the first draft-stream preview update (30-char threshold) and finalize short responses by editing the stop-time preview message, improving first push notifications and avoiding duplicate final sends. (#18148) Thanks @Marvae.
|
||||
|
||||
@@ -253,6 +253,15 @@ describe("resolveCommandAuthorization", () => {
|
||||
} as MsgContext;
|
||||
}
|
||||
|
||||
function makeDiscordContext(senderId: string, fromOverride?: string): MsgContext {
|
||||
return {
|
||||
Provider: "discord",
|
||||
Surface: "discord",
|
||||
From: fromOverride ?? `discord:${senderId}`,
|
||||
SenderId: senderId,
|
||||
} as MsgContext;
|
||||
}
|
||||
|
||||
function resolveWithCommandsAllowFrom(senderId: string, commandAuthorized: boolean) {
|
||||
return resolveCommandAuthorization({
|
||||
ctx: makeWhatsAppContext(senderId),
|
||||
@@ -372,6 +381,48 @@ describe("resolveCommandAuthorization", () => {
|
||||
|
||||
expect(auth.isAuthorizedSender).toBe(true);
|
||||
});
|
||||
|
||||
it("normalizes Discord commands.allowFrom prefixes and mentions", () => {
|
||||
const cfg = {
|
||||
commands: {
|
||||
allowFrom: {
|
||||
discord: ["user:123", "<@!456>", "pk:member-1"],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const userAuth = resolveCommandAuthorization({
|
||||
ctx: makeDiscordContext("123"),
|
||||
cfg,
|
||||
commandAuthorized: false,
|
||||
});
|
||||
|
||||
expect(userAuth.isAuthorizedSender).toBe(true);
|
||||
|
||||
const mentionAuth = resolveCommandAuthorization({
|
||||
ctx: makeDiscordContext("456"),
|
||||
cfg,
|
||||
commandAuthorized: false,
|
||||
});
|
||||
|
||||
expect(mentionAuth.isAuthorizedSender).toBe(true);
|
||||
|
||||
const pkAuth = resolveCommandAuthorization({
|
||||
ctx: makeDiscordContext("member-1", "discord:999"),
|
||||
cfg,
|
||||
commandAuthorized: false,
|
||||
});
|
||||
|
||||
expect(pkAuth.isAuthorizedSender).toBe(true);
|
||||
|
||||
const deniedAuth = resolveCommandAuthorization({
|
||||
ctx: makeDiscordContext("other"),
|
||||
cfg,
|
||||
commandAuthorized: false,
|
||||
});
|
||||
|
||||
expect(deniedAuth.isAuthorizedSender).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -82,6 +82,21 @@ const formatLower = (allowFrom: Array<string | number>) =>
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.toLowerCase());
|
||||
|
||||
const formatDiscordAllowFrom = (allowFrom: Array<string | number>) =>
|
||||
allowFrom
|
||||
.map((entry) =>
|
||||
String(entry)
|
||||
.trim()
|
||||
.replace(/^<@!?/, "")
|
||||
.replace(/>$/, "")
|
||||
.replace(/^discord:/i, "")
|
||||
.replace(/^user:/i, "")
|
||||
.replace(/^pk:/i, "")
|
||||
.trim()
|
||||
.toLowerCase(),
|
||||
)
|
||||
.filter(Boolean);
|
||||
|
||||
function buildDirectOrGroupThreadToolContext(params: {
|
||||
context: ChannelThreadingContext;
|
||||
hasRepliedRef: ChannelThreadingToolContext["hasRepliedRef"];
|
||||
@@ -218,17 +233,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
|
||||
String(entry),
|
||||
);
|
||||
},
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) =>
|
||||
entry
|
||||
.replace(/^discord:/i, "")
|
||||
.replace(/^user:/i, "")
|
||||
.replace(/^pk:/i, "")
|
||||
.toLowerCase(),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) => formatDiscordAllowFrom(allowFrom),
|
||||
},
|
||||
groups: {
|
||||
resolveRequireMention: resolveDiscordGroupRequireMention,
|
||||
|
||||
Reference in New Issue
Block a user