
























@@ -9,10 +9,12 @@ export function normalizeDiscordMessagingTarget(raw: string): string | undefined
99/**
1010 * Normalize a Discord outbound target for delivery. Bare numeric IDs are
1111 * prefixed with "channel:" to avoid the ambiguous-target error in
12- * parseDiscordTarget. All other formats pass through unchanged.
12+ * parseDiscordTarget, unless the ID is explicitly configured as an allowed DM
13+ * sender. All other formats pass through unchanged.
1314 */
1415export function normalizeDiscordOutboundTarget(
1516to?: string,
17+allowFrom?: readonly string[],
1618): { ok: true; to: string } | { ok: false; error: Error } {
1719const trimmed = to?.trim();
1820if (!trimmed) {
@@ -24,11 +26,48 @@ export function normalizeDiscordOutboundTarget(
2426};
2527}
2628if (/^\d+$/.test(trimmed)) {
29+if (allowFromContainsDiscordUserId(allowFrom, trimmed)) {
30+return { ok: true, to: `user:${trimmed}` };
31+}
2732return { ok: true, to: `channel:${trimmed}` };
2833}
2934return { ok: true, to: trimmed };
3035}
313637+export function allowFromContainsDiscordUserId(
38+allowFrom: readonly string[] | undefined,
39+userId: string,
40+): boolean {
41+const normalizedUserId = userId.trim();
42+if (!normalizedUserId) {
43+return false;
44+}
45+return (allowFrom ?? []).some(
46+(entry) => normalizeAllowFromDiscordUserId(entry) === normalizedUserId,
47+);
48+}
49+50+function normalizeAllowFromDiscordUserId(entry: string): string | undefined {
51+const trimmed = entry.trim().toLowerCase();
52+if (!trimmed || trimmed === "*") {
53+return undefined;
54+}
55+const mentionMatch = /^<@!?(\d+)>$/.exec(trimmed);
56+if (mentionMatch) {
57+return mentionMatch[1];
58+}
59+// Accept both current and legacy allowFrom forms for Discord user IDs.
60+const prefixedMatch = /^(?:discord:)?user:(\d+)$/.exec(trimmed);
61+if (prefixedMatch) {
62+return prefixedMatch[1];
63+}
64+const discordMatch = /^discord:(\d+)$/.exec(trimmed);
65+if (discordMatch) {
66+return discordMatch[1];
67+}
68+return /^\d+$/.test(trimmed) ? trimmed : undefined;
69+}
70+3271export function looksLikeDiscordTargetId(raw: string): boolean {
3372const trimmed = raw.trim();
3473if (!trimmed) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。