Files
openclaw/src/discord/monitor/dm-command-auth.ts
2026-03-02 00:00:05 +00:00

105 lines
3.1 KiB
TypeScript

import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
import {
readStoreAllowFromForDmPolicy,
resolveDmGroupAccessWithLists,
type DmGroupAccessDecision,
} from "../../security/dm-policy-shared.js";
import { normalizeDiscordAllowList, resolveDiscordAllowListMatch } from "./allow-list.js";
const DISCORD_ALLOW_LIST_PREFIXES = ["discord:", "user:", "pk:"];
export type DiscordDmPolicy = "open" | "pairing" | "allowlist" | "disabled";
export type DiscordDmCommandAccess = {
decision: DmGroupAccessDecision;
reason: string;
commandAuthorized: boolean;
allowMatch: ReturnType<typeof resolveDiscordAllowListMatch> | { allowed: false };
};
function resolveSenderAllowMatch(params: {
allowEntries: string[];
sender: { id: string; name?: string; tag?: string };
allowNameMatching: boolean;
}) {
const allowList = normalizeDiscordAllowList(params.allowEntries, DISCORD_ALLOW_LIST_PREFIXES);
return allowList
? resolveDiscordAllowListMatch({
allowList,
candidate: params.sender,
allowNameMatching: params.allowNameMatching,
})
: ({ allowed: false } as const);
}
function resolveDmPolicyCommandAuthorization(params: {
dmPolicy: DiscordDmPolicy;
decision: DmGroupAccessDecision;
commandAuthorized: boolean;
}) {
if (params.dmPolicy === "open" && params.decision === "allow") {
return true;
}
return params.commandAuthorized;
}
export async function resolveDiscordDmCommandAccess(params: {
accountId: string;
dmPolicy: DiscordDmPolicy;
configuredAllowFrom: string[];
sender: { id: string; name?: string; tag?: string };
allowNameMatching: boolean;
useAccessGroups: boolean;
readStoreAllowFrom?: () => Promise<string[]>;
}): Promise<DiscordDmCommandAccess> {
const storeAllowFrom = params.readStoreAllowFrom
? await params.readStoreAllowFrom().catch(() => [])
: await readStoreAllowFromForDmPolicy({
provider: "discord",
accountId: params.accountId,
dmPolicy: params.dmPolicy,
});
const access = resolveDmGroupAccessWithLists({
isGroup: false,
dmPolicy: params.dmPolicy,
allowFrom: params.configuredAllowFrom,
groupAllowFrom: [],
storeAllowFrom,
isSenderAllowed: (allowEntries) =>
resolveSenderAllowMatch({
allowEntries,
sender: params.sender,
allowNameMatching: params.allowNameMatching,
}).allowed,
});
const allowMatch = resolveSenderAllowMatch({
allowEntries: access.effectiveAllowFrom,
sender: params.sender,
allowNameMatching: params.allowNameMatching,
});
const commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
useAccessGroups: params.useAccessGroups,
authorizers: [
{
configured: access.effectiveAllowFrom.length > 0,
allowed: allowMatch.allowed,
},
],
modeWhenAccessGroupsOff: "configured",
});
return {
decision: access.decision,
reason: access.reason,
commandAuthorized: resolveDmPolicyCommandAuthorization({
dmPolicy: params.dmPolicy,
decision: access.decision,
commandAuthorized,
}),
allowMatch,
};
}