186 lines
5.9 KiB
TypeScript
186 lines
5.9 KiB
TypeScript
import type { ChannelId } from "../channels/plugins/types.js";
|
|
import { normalizeAccountId } from "../routing/session-key.js";
|
|
import type { MoltbotConfig } from "./config.js";
|
|
import type { GroupToolPolicyBySenderConfig, GroupToolPolicyConfig } from "./types.tools.js";
|
|
|
|
export type GroupPolicyChannel = ChannelId;
|
|
|
|
export type ChannelGroupConfig = {
|
|
requireMention?: boolean;
|
|
tools?: GroupToolPolicyConfig;
|
|
toolsBySender?: GroupToolPolicyBySenderConfig;
|
|
};
|
|
|
|
export type ChannelGroupPolicy = {
|
|
allowlistEnabled: boolean;
|
|
allowed: boolean;
|
|
groupConfig?: ChannelGroupConfig;
|
|
defaultConfig?: ChannelGroupConfig;
|
|
};
|
|
|
|
type ChannelGroups = Record<string, ChannelGroupConfig>;
|
|
|
|
export type GroupToolPolicySender = {
|
|
senderId?: string | null;
|
|
senderName?: string | null;
|
|
senderUsername?: string | null;
|
|
senderE164?: string | null;
|
|
};
|
|
|
|
function normalizeSenderKey(value: string): string {
|
|
const trimmed = value.trim();
|
|
if (!trimmed) return "";
|
|
const withoutAt = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
return withoutAt.toLowerCase();
|
|
}
|
|
|
|
export function resolveToolsBySender(
|
|
params: {
|
|
toolsBySender?: GroupToolPolicyBySenderConfig;
|
|
} & GroupToolPolicySender,
|
|
): GroupToolPolicyConfig | undefined {
|
|
const toolsBySender = params.toolsBySender;
|
|
if (!toolsBySender) return undefined;
|
|
const entries = Object.entries(toolsBySender);
|
|
if (entries.length === 0) return undefined;
|
|
|
|
const normalized = new Map<string, GroupToolPolicyConfig>();
|
|
let wildcard: GroupToolPolicyConfig | undefined;
|
|
for (const [rawKey, policy] of entries) {
|
|
if (!policy) continue;
|
|
const key = normalizeSenderKey(rawKey);
|
|
if (!key) continue;
|
|
if (key === "*") {
|
|
wildcard = policy;
|
|
continue;
|
|
}
|
|
if (!normalized.has(key)) {
|
|
normalized.set(key, policy);
|
|
}
|
|
}
|
|
|
|
const candidates: string[] = [];
|
|
const pushCandidate = (value?: string | null) => {
|
|
const trimmed = value?.trim();
|
|
if (!trimmed) return;
|
|
candidates.push(trimmed);
|
|
};
|
|
pushCandidate(params.senderId);
|
|
pushCandidate(params.senderE164);
|
|
pushCandidate(params.senderUsername);
|
|
pushCandidate(params.senderName);
|
|
|
|
for (const candidate of candidates) {
|
|
const key = normalizeSenderKey(candidate);
|
|
if (!key) continue;
|
|
const match = normalized.get(key);
|
|
if (match) return match;
|
|
}
|
|
return wildcard;
|
|
}
|
|
|
|
function resolveChannelGroups(
|
|
cfg: MoltbotConfig,
|
|
channel: GroupPolicyChannel,
|
|
accountId?: string | null,
|
|
): ChannelGroups | undefined {
|
|
const normalizedAccountId = normalizeAccountId(accountId);
|
|
const channelConfig = cfg.channels?.[channel] as
|
|
| {
|
|
accounts?: Record<string, { groups?: ChannelGroups }>;
|
|
groups?: ChannelGroups;
|
|
}
|
|
| undefined;
|
|
if (!channelConfig) return undefined;
|
|
const accountGroups =
|
|
channelConfig.accounts?.[normalizedAccountId]?.groups ??
|
|
channelConfig.accounts?.[
|
|
Object.keys(channelConfig.accounts ?? {}).find(
|
|
(key) => key.toLowerCase() === normalizedAccountId.toLowerCase(),
|
|
) ?? ""
|
|
]?.groups;
|
|
return accountGroups ?? channelConfig.groups;
|
|
}
|
|
|
|
export function resolveChannelGroupPolicy(params: {
|
|
cfg: MoltbotConfig;
|
|
channel: GroupPolicyChannel;
|
|
groupId?: string | null;
|
|
accountId?: string | null;
|
|
}): ChannelGroupPolicy {
|
|
const { cfg, channel } = params;
|
|
const groups = resolveChannelGroups(cfg, channel, params.accountId);
|
|
const allowlistEnabled = Boolean(groups && Object.keys(groups).length > 0);
|
|
const normalizedId = params.groupId?.trim();
|
|
const groupConfig = normalizedId && groups ? groups[normalizedId] : undefined;
|
|
const defaultConfig = groups?.["*"];
|
|
const allowAll = allowlistEnabled && Boolean(groups && Object.hasOwn(groups, "*"));
|
|
const allowed =
|
|
!allowlistEnabled ||
|
|
allowAll ||
|
|
(normalizedId ? Boolean(groups && Object.hasOwn(groups, normalizedId)) : false);
|
|
return {
|
|
allowlistEnabled,
|
|
allowed,
|
|
groupConfig,
|
|
defaultConfig,
|
|
};
|
|
}
|
|
|
|
export function resolveChannelGroupRequireMention(params: {
|
|
cfg: MoltbotConfig;
|
|
channel: GroupPolicyChannel;
|
|
groupId?: string | null;
|
|
accountId?: string | null;
|
|
requireMentionOverride?: boolean;
|
|
overrideOrder?: "before-config" | "after-config";
|
|
}): boolean {
|
|
const { requireMentionOverride, overrideOrder = "after-config" } = params;
|
|
const { groupConfig, defaultConfig } = resolveChannelGroupPolicy(params);
|
|
const configMention =
|
|
typeof groupConfig?.requireMention === "boolean"
|
|
? groupConfig.requireMention
|
|
: typeof defaultConfig?.requireMention === "boolean"
|
|
? defaultConfig.requireMention
|
|
: undefined;
|
|
|
|
if (overrideOrder === "before-config" && typeof requireMentionOverride === "boolean") {
|
|
return requireMentionOverride;
|
|
}
|
|
if (typeof configMention === "boolean") return configMention;
|
|
if (overrideOrder !== "before-config" && typeof requireMentionOverride === "boolean") {
|
|
return requireMentionOverride;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function resolveChannelGroupToolsPolicy(
|
|
params: {
|
|
cfg: MoltbotConfig;
|
|
channel: GroupPolicyChannel;
|
|
groupId?: string | null;
|
|
accountId?: string | null;
|
|
} & GroupToolPolicySender,
|
|
): GroupToolPolicyConfig | undefined {
|
|
const { groupConfig, defaultConfig } = resolveChannelGroupPolicy(params);
|
|
const groupSenderPolicy = resolveToolsBySender({
|
|
toolsBySender: groupConfig?.toolsBySender,
|
|
senderId: params.senderId,
|
|
senderName: params.senderName,
|
|
senderUsername: params.senderUsername,
|
|
senderE164: params.senderE164,
|
|
});
|
|
if (groupSenderPolicy) return groupSenderPolicy;
|
|
if (groupConfig?.tools) return groupConfig.tools;
|
|
const defaultSenderPolicy = resolveToolsBySender({
|
|
toolsBySender: defaultConfig?.toolsBySender,
|
|
senderId: params.senderId,
|
|
senderName: params.senderName,
|
|
senderUsername: params.senderUsername,
|
|
senderE164: params.senderE164,
|
|
});
|
|
if (defaultSenderPolicy) return defaultSenderPolicy;
|
|
if (defaultConfig?.tools) return defaultConfig.tools;
|
|
return undefined;
|
|
}
|