mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-13 06:00:34 +00:00
refactor(discord): split allowlist resolution flow
This commit is contained in:
@@ -108,17 +108,19 @@ export function patchAllowlistUsersInConfigEntries<
|
|||||||
if (!Array.isArray(users) || users.length === 0) {
|
if (!Array.isArray(users) || users.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const additions = resolveAllowlistIdAdditions({
|
|
||||||
existing: users,
|
|
||||||
resolvedMap: params.resolvedMap,
|
|
||||||
});
|
|
||||||
const resolvedUsers =
|
const resolvedUsers =
|
||||||
params.strategy === "canonicalize"
|
params.strategy === "canonicalize"
|
||||||
? canonicalizeAllowlistWithResolvedIds({
|
? canonicalizeAllowlistWithResolvedIds({
|
||||||
existing: users,
|
existing: users,
|
||||||
resolvedMap: params.resolvedMap,
|
resolvedMap: params.resolvedMap,
|
||||||
})
|
})
|
||||||
: mergeAllowlist({ existing: users, additions });
|
: mergeAllowlist({
|
||||||
|
existing: users,
|
||||||
|
additions: resolveAllowlistIdAdditions({
|
||||||
|
existing: users,
|
||||||
|
resolvedMap: params.resolvedMap,
|
||||||
|
}),
|
||||||
|
});
|
||||||
nextEntries[entryKey] = {
|
nextEntries[entryKey] = {
|
||||||
...entryConfig,
|
...entryConfig,
|
||||||
users: resolvedUsers,
|
users: resolvedUsers,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { resolveDiscordChannelAllowlist } from "../resolve-channels.js";
|
|||||||
import { resolveDiscordUserAllowlist } from "../resolve-users.js";
|
import { resolveDiscordUserAllowlist } from "../resolve-users.js";
|
||||||
|
|
||||||
type GuildEntries = Record<string, DiscordGuildEntry>;
|
type GuildEntries = Record<string, DiscordGuildEntry>;
|
||||||
|
type ChannelResolutionInput = { input: string; guildKey: string; channelKey?: string };
|
||||||
|
|
||||||
function toGuildEntries(value: unknown): GuildEntries {
|
function toGuildEntries(value: unknown): GuildEntries {
|
||||||
if (!value || typeof value !== "object") {
|
if (!value || typeof value !== "object") {
|
||||||
@@ -34,19 +35,12 @@ function toAllowlistEntries(value: unknown): string[] | undefined {
|
|||||||
return value.map((entry) => String(entry).trim()).filter((entry) => Boolean(entry));
|
return value.map((entry) => String(entry).trim()).filter((entry) => Boolean(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveDiscordAllowlistConfig(params: {
|
function hasGuildEntries(value: GuildEntries): boolean {
|
||||||
token: string;
|
return Object.keys(value).length > 0;
|
||||||
guildEntries: unknown;
|
}
|
||||||
allowFrom: unknown;
|
|
||||||
fetcher: typeof fetch;
|
|
||||||
runtime: RuntimeEnv;
|
|
||||||
}): Promise<{ guildEntries: GuildEntries | undefined; allowFrom: string[] | undefined }> {
|
|
||||||
let guildEntries = toGuildEntries(params.guildEntries);
|
|
||||||
let allowFrom = toAllowlistEntries(params.allowFrom);
|
|
||||||
|
|
||||||
if (Object.keys(guildEntries).length > 0) {
|
function collectChannelResolutionInputs(guildEntries: GuildEntries): ChannelResolutionInput[] {
|
||||||
try {
|
const entries: ChannelResolutionInput[] = [];
|
||||||
const entries: Array<{ input: string; guildKey: string; channelKey?: string }> = [];
|
|
||||||
for (const [guildKey, guildCfg] of Object.entries(guildEntries)) {
|
for (const [guildKey, guildCfg] of Object.entries(guildEntries)) {
|
||||||
if (guildKey === "*") {
|
if (guildKey === "*") {
|
||||||
continue;
|
continue;
|
||||||
@@ -66,21 +60,35 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entries.length > 0) {
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveGuildEntriesByChannelAllowlist(params: {
|
||||||
|
token: string;
|
||||||
|
guildEntries: GuildEntries;
|
||||||
|
fetcher: typeof fetch;
|
||||||
|
runtime: RuntimeEnv;
|
||||||
|
}): Promise<GuildEntries> {
|
||||||
|
const entries = collectChannelResolutionInputs(params.guildEntries);
|
||||||
|
if (entries.length === 0) {
|
||||||
|
return params.guildEntries;
|
||||||
|
}
|
||||||
|
try {
|
||||||
const resolved = await resolveDiscordChannelAllowlist({
|
const resolved = await resolveDiscordChannelAllowlist({
|
||||||
token: params.token,
|
token: params.token,
|
||||||
entries: entries.map((entry) => entry.input),
|
entries: entries.map((entry) => entry.input),
|
||||||
fetcher: params.fetcher,
|
fetcher: params.fetcher,
|
||||||
});
|
});
|
||||||
const nextGuilds = { ...guildEntries };
|
const sourceByInput = new Map(entries.map((entry) => [entry.input, entry]));
|
||||||
|
const nextGuilds = { ...params.guildEntries };
|
||||||
const mapping: string[] = [];
|
const mapping: string[] = [];
|
||||||
const unresolved: string[] = [];
|
const unresolved: string[] = [];
|
||||||
for (const entry of resolved) {
|
for (const entry of resolved) {
|
||||||
const source = entries.find((item) => item.input === entry.input);
|
const source = sourceByInput.get(entry.input);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const sourceGuild = guildEntries[source.guildKey] ?? {};
|
const sourceGuild = params.guildEntries[source.guildKey] ?? {};
|
||||||
if (!entry.resolved || !entry.guildId) {
|
if (!entry.resolved || !entry.guildId) {
|
||||||
unresolved.push(entry.input);
|
unresolved.push(entry.input);
|
||||||
continue;
|
continue;
|
||||||
@@ -118,19 +126,27 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guildEntries = nextGuilds;
|
|
||||||
summarizeMapping("discord channels", mapping, unresolved, params.runtime);
|
summarizeMapping("discord channels", mapping, unresolved, params.runtime);
|
||||||
}
|
return nextGuilds;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
params.runtime.log?.(
|
params.runtime.log?.(
|
||||||
`discord channel resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
`discord channel resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
||||||
);
|
);
|
||||||
|
return params.guildEntries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resolveAllowFromByUserAllowlist(params: {
|
||||||
|
token: string;
|
||||||
|
allowFrom: string[] | undefined;
|
||||||
|
fetcher: typeof fetch;
|
||||||
|
runtime: RuntimeEnv;
|
||||||
|
}): Promise<string[] | undefined> {
|
||||||
const allowEntries =
|
const allowEntries =
|
||||||
allowFrom?.filter((entry) => String(entry).trim() && String(entry).trim() !== "*") ?? [];
|
params.allowFrom?.filter((entry) => String(entry).trim() && String(entry).trim() !== "*") ?? [];
|
||||||
if (allowEntries.length > 0) {
|
if (allowEntries.length === 0) {
|
||||||
|
return params.allowFrom;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const resolvedUsers = await resolveDiscordUserAllowlist({
|
const resolvedUsers = await resolveDiscordUserAllowlist({
|
||||||
token: params.token,
|
token: params.token,
|
||||||
@@ -138,19 +154,21 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
fetcher: params.fetcher,
|
fetcher: params.fetcher,
|
||||||
});
|
});
|
||||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
||||||
allowFrom = canonicalizeAllowlistWithResolvedIds({
|
const allowFrom = canonicalizeAllowlistWithResolvedIds({
|
||||||
existing: allowFrom,
|
existing: params.allowFrom,
|
||||||
resolvedMap,
|
resolvedMap,
|
||||||
});
|
});
|
||||||
summarizeMapping("discord users", mapping, unresolved, params.runtime);
|
summarizeMapping("discord users", mapping, unresolved, params.runtime);
|
||||||
|
return allowFrom;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
params.runtime.log?.(
|
params.runtime.log?.(
|
||||||
`discord user resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
`discord user resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
||||||
);
|
);
|
||||||
|
return params.allowFrom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(guildEntries).length > 0) {
|
function collectGuildUserEntries(guildEntries: GuildEntries): Set<string> {
|
||||||
const userEntries = new Set<string>();
|
const userEntries = new Set<string>();
|
||||||
for (const guild of Object.values(guildEntries)) {
|
for (const guild of Object.values(guildEntries)) {
|
||||||
if (!guild || typeof guild !== "object") {
|
if (!guild || typeof guild !== "object") {
|
||||||
@@ -162,8 +180,19 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return userEntries;
|
||||||
|
}
|
||||||
|
|
||||||
if (userEntries.size > 0) {
|
async function resolveGuildEntriesByUserAllowlist(params: {
|
||||||
|
token: string;
|
||||||
|
guildEntries: GuildEntries;
|
||||||
|
fetcher: typeof fetch;
|
||||||
|
runtime: RuntimeEnv;
|
||||||
|
}): Promise<GuildEntries> {
|
||||||
|
const userEntries = collectGuildUserEntries(params.guildEntries);
|
||||||
|
if (userEntries.size === 0) {
|
||||||
|
return params.guildEntries;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const resolvedUsers = await resolveDiscordUserAllowlist({
|
const resolvedUsers = await resolveDiscordUserAllowlist({
|
||||||
token: params.token,
|
token: params.token,
|
||||||
@@ -171,9 +200,8 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
fetcher: params.fetcher,
|
fetcher: params.fetcher,
|
||||||
});
|
});
|
||||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
||||||
|
const nextGuilds = { ...params.guildEntries };
|
||||||
const nextGuilds = { ...guildEntries };
|
for (const [guildKey, guildConfig] of Object.entries(params.guildEntries)) {
|
||||||
for (const [guildKey, guildConfig] of Object.entries(guildEntries ?? {})) {
|
|
||||||
if (!guildConfig || typeof guildConfig !== "object") {
|
if (!guildConfig || typeof guildConfig !== "object") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -195,18 +223,53 @@ export async function resolveDiscordAllowlistConfig(params: {
|
|||||||
}
|
}
|
||||||
nextGuilds[guildKey] = nextGuild as DiscordGuildEntry;
|
nextGuilds[guildKey] = nextGuild as DiscordGuildEntry;
|
||||||
}
|
}
|
||||||
guildEntries = nextGuilds;
|
|
||||||
summarizeMapping("discord channel users", mapping, unresolved, params.runtime);
|
summarizeMapping("discord channel users", mapping, unresolved, params.runtime);
|
||||||
|
return nextGuilds;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
params.runtime.log?.(
|
params.runtime.log?.(
|
||||||
`discord channel user resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
`discord channel user resolve failed; using config entries. ${formatErrorMessage(err)}`,
|
||||||
);
|
);
|
||||||
}
|
return params.guildEntries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function resolveDiscordAllowlistConfig(params: {
|
||||||
|
token: string;
|
||||||
|
guildEntries: unknown;
|
||||||
|
allowFrom: unknown;
|
||||||
|
fetcher: typeof fetch;
|
||||||
|
runtime: RuntimeEnv;
|
||||||
|
}): Promise<{ guildEntries: GuildEntries | undefined; allowFrom: string[] | undefined }> {
|
||||||
|
let guildEntries = toGuildEntries(params.guildEntries);
|
||||||
|
let allowFrom = toAllowlistEntries(params.allowFrom);
|
||||||
|
|
||||||
|
if (hasGuildEntries(guildEntries)) {
|
||||||
|
guildEntries = await resolveGuildEntriesByChannelAllowlist({
|
||||||
|
token: params.token,
|
||||||
|
guildEntries,
|
||||||
|
fetcher: params.fetcher,
|
||||||
|
runtime: params.runtime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
allowFrom = await resolveAllowFromByUserAllowlist({
|
||||||
|
token: params.token,
|
||||||
|
allowFrom,
|
||||||
|
fetcher: params.fetcher,
|
||||||
|
runtime: params.runtime,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasGuildEntries(guildEntries)) {
|
||||||
|
guildEntries = await resolveGuildEntriesByUserAllowlist({
|
||||||
|
token: params.token,
|
||||||
|
guildEntries,
|
||||||
|
fetcher: params.fetcher,
|
||||||
|
runtime: params.runtime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
guildEntries: Object.keys(guildEntries).length > 0 ? guildEntries : undefined,
|
guildEntries: hasGuildEntries(guildEntries) ? guildEntries : undefined,
|
||||||
allowFrom,
|
allowFrom,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user