mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 13:31:25 +00:00
Discord: add PluralKit sender identity resolver (#5838)
* Discord: add PluralKit sender identity resolver * fix: resolve PluralKit sender identities (#5838) (thanks @thewilloftheshadow)
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import { ChannelType, MessageType, type User } from "@buape/carbon";
|
||||
import type {
|
||||
DiscordMessagePreflightContext,
|
||||
DiscordMessagePreflightParams,
|
||||
} from "./message-handler.preflight.types.js";
|
||||
|
||||
import { hasControlCommand } from "../../auto-reply/command-detection.js";
|
||||
import { shouldHandleTextCommands } from "../../auto-reply/commands-registry.js";
|
||||
import {
|
||||
@@ -27,6 +24,7 @@ import {
|
||||
upsertChannelPairingRequest,
|
||||
} from "../../pairing/pairing-store.js";
|
||||
import { resolveAgentRoute } from "../../routing/resolve-route.js";
|
||||
import { fetchPluralKitMessageInfo } from "../pluralkit.js";
|
||||
import { sendMessageDiscord } from "../send.js";
|
||||
import {
|
||||
allowListMatches,
|
||||
@@ -45,13 +43,19 @@ import {
|
||||
resolveDiscordSystemLocation,
|
||||
resolveTimestampMs,
|
||||
} from "./format.js";
|
||||
import type {
|
||||
DiscordMessagePreflightContext,
|
||||
DiscordMessagePreflightParams,
|
||||
} from "./message-handler.preflight.types.js";
|
||||
import { resolveDiscordChannelInfo, resolveDiscordMessageText } from "./message-utils.js";
|
||||
import { resolveDiscordSenderIdentity, resolveDiscordWebhookId } from "./sender-identity.js";
|
||||
import { resolveDiscordSystemEvent } from "./system-events.js";
|
||||
import { resolveDiscordThreadChannel, resolveDiscordThreadParentInfo } from "./threading.js";
|
||||
|
||||
export type {
|
||||
DiscordMessagePreflightContext,
|
||||
DiscordMessagePreflightParams,
|
||||
DiscordSenderIdentity,
|
||||
} from "./message-handler.preflight.types.js";
|
||||
|
||||
export async function preflightDiscordMessage(
|
||||
@@ -65,12 +69,33 @@ export async function preflightDiscordMessage(
|
||||
}
|
||||
|
||||
const allowBots = params.discordConfig?.allowBots ?? false;
|
||||
if (author.bot) {
|
||||
if (author.bot && params.botUserId && author.id === params.botUserId) {
|
||||
// Always ignore own messages to prevent self-reply loops
|
||||
if (params.botUserId && author.id === params.botUserId) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
const pluralkitConfig = params.discordConfig?.pluralkit;
|
||||
const webhookId = resolveDiscordWebhookId(message);
|
||||
const shouldCheckPluralKit = Boolean(pluralkitConfig?.enabled) && !webhookId;
|
||||
let pluralkitInfo: Awaited<ReturnType<typeof fetchPluralKitMessageInfo>> = null;
|
||||
if (shouldCheckPluralKit) {
|
||||
try {
|
||||
pluralkitInfo = await fetchPluralKitMessageInfo({
|
||||
messageId: message.id,
|
||||
config: pluralkitConfig,
|
||||
});
|
||||
} catch (err) {
|
||||
logVerbose(`discord: pluralkit lookup failed for ${message.id}: ${String(err)}`);
|
||||
}
|
||||
if (!allowBots) {
|
||||
}
|
||||
const sender = resolveDiscordSenderIdentity({
|
||||
author,
|
||||
member: params.data.member,
|
||||
pluralkitInfo,
|
||||
});
|
||||
|
||||
if (author.bot) {
|
||||
if (!allowBots && !sender.isPluralKit) {
|
||||
logVerbose("discord: drop bot message (allowBots=false)");
|
||||
return null;
|
||||
}
|
||||
@@ -100,14 +125,14 @@ export async function preflightDiscordMessage(
|
||||
if (dmPolicy !== "open") {
|
||||
const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
|
||||
const effectiveAllowFrom = [...(params.allowFrom ?? []), ...storeAllowFrom];
|
||||
const allowList = normalizeDiscordAllowList(effectiveAllowFrom, ["discord:", "user:"]);
|
||||
const allowList = normalizeDiscordAllowList(effectiveAllowFrom, ["discord:", "user:", "pk:"]);
|
||||
const allowMatch = allowList
|
||||
? resolveDiscordAllowListMatch({
|
||||
allowList,
|
||||
candidate: {
|
||||
id: author.id,
|
||||
name: author.username,
|
||||
tag: formatDiscordUserTag(author),
|
||||
id: sender.id,
|
||||
name: sender.name,
|
||||
tag: sender.tag,
|
||||
},
|
||||
})
|
||||
: { allowed: false };
|
||||
@@ -148,7 +173,7 @@ export async function preflightDiscordMessage(
|
||||
}
|
||||
} else {
|
||||
logVerbose(
|
||||
`Blocked unauthorized discord sender ${author.id} (dmPolicy=${dmPolicy}, ${allowMatchMeta})`,
|
||||
`Blocked unauthorized discord sender ${sender.id} (dmPolicy=${dmPolicy}, ${allowMatchMeta})`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -349,7 +374,7 @@ export async function preflightDiscordMessage(
|
||||
const historyEntry =
|
||||
isGuildMessage && params.historyLimit > 0 && textForHistory
|
||||
? ({
|
||||
sender: params.data.member?.nickname ?? author.globalName ?? author.username ?? author.id,
|
||||
sender: sender.label,
|
||||
body: textForHistory,
|
||||
timestamp: resolveTimestampMs(message.timestamp),
|
||||
messageId: message.id,
|
||||
@@ -372,12 +397,16 @@ export async function preflightDiscordMessage(
|
||||
const hasControlCommandInMessage = hasControlCommand(baseText, params.cfg);
|
||||
|
||||
if (!isDirectMessage) {
|
||||
const ownerAllowList = normalizeDiscordAllowList(params.allowFrom, ["discord:", "user:"]);
|
||||
const ownerAllowList = normalizeDiscordAllowList(params.allowFrom, [
|
||||
"discord:",
|
||||
"user:",
|
||||
"pk:",
|
||||
]);
|
||||
const ownerOk = ownerAllowList
|
||||
? allowListMatches(ownerAllowList, {
|
||||
id: author.id,
|
||||
name: author.username,
|
||||
tag: formatDiscordUserTag(author),
|
||||
id: sender.id,
|
||||
name: sender.name,
|
||||
tag: sender.tag,
|
||||
})
|
||||
: false;
|
||||
const channelUsers = channelConfig?.users ?? guildInfo?.users;
|
||||
@@ -385,9 +414,9 @@ export async function preflightDiscordMessage(
|
||||
Array.isArray(channelUsers) && channelUsers.length > 0
|
||||
? resolveDiscordUserAllowed({
|
||||
allowList: channelUsers,
|
||||
userId: author.id,
|
||||
userName: author.username,
|
||||
userTag: formatDiscordUserTag(author),
|
||||
userId: sender.id,
|
||||
userName: sender.name,
|
||||
userTag: sender.tag,
|
||||
})
|
||||
: false;
|
||||
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
|
||||
@@ -408,7 +437,7 @@ export async function preflightDiscordMessage(
|
||||
log: logVerbose,
|
||||
channel: "discord",
|
||||
reason: "control command (unauthorized)",
|
||||
target: author.id,
|
||||
target: sender.id,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
@@ -452,12 +481,12 @@ export async function preflightDiscordMessage(
|
||||
if (Array.isArray(channelUsers) && channelUsers.length > 0) {
|
||||
const userOk = resolveDiscordUserAllowed({
|
||||
allowList: channelUsers,
|
||||
userId: author.id,
|
||||
userName: author.username,
|
||||
userTag: formatDiscordUserTag(author),
|
||||
userId: sender.id,
|
||||
userName: sender.name,
|
||||
userTag: sender.tag,
|
||||
});
|
||||
if (!userOk) {
|
||||
logVerbose(`Blocked discord guild sender ${author.id} (not in channel users allowlist)`);
|
||||
logVerbose(`Blocked discord guild sender ${sender.id} (not in channel users allowlist)`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -501,6 +530,7 @@ export async function preflightDiscordMessage(
|
||||
client: params.client,
|
||||
message,
|
||||
author,
|
||||
sender,
|
||||
channelInfo,
|
||||
channelName,
|
||||
isGuildMessage,
|
||||
|
||||
Reference in New Issue
Block a user