From df3aa90a20ada07e141af24050bf831040f5d494 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Mon, 20 Apr 2026 09:56:37 +0530 Subject: [PATCH] fix(telegram): require numeric allowFrom ids in setup --- extensions/telegram/src/setup-core.ts | 56 +++---------------- extensions/telegram/src/setup-surface.test.ts | 41 ++++---------- extensions/telegram/src/setup-surface.ts | 17 +++--- 3 files changed, 25 insertions(+), 89 deletions(-) diff --git a/extensions/telegram/src/setup-core.ts b/extensions/telegram/src/setup-core.ts index 35534a4d1b9..7dea658a105 100644 --- a/extensions/telegram/src/setup-core.ts +++ b/extensions/telegram/src/setup-core.ts @@ -1,4 +1,3 @@ -import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/setup-runtime"; import { createEnvPatchedAccountSetupAdapter, @@ -11,7 +10,6 @@ import { import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools"; import { resolveDefaultTelegramAccountId, resolveTelegramAccount } from "./accounts.js"; import { isNumericTelegramSenderUserId } from "./allow-from.js"; -import { lookupTelegramChatId } from "./api-fetch.js"; const channel = "telegram" as const; @@ -44,36 +42,6 @@ export function parseTelegramAllowFromId(raw: string): string | null { return isNumericTelegramSenderUserId(stripped) ? stripped : null; } -export async function resolveTelegramAllowFromEntries(params: { - entries: string[]; - credentialValue?: string; - apiRoot?: string; - proxyUrl?: string; - network?: TelegramNetworkConfig; -}) { - return await Promise.all( - params.entries.map(async (entry) => { - const numericId = parseTelegramAllowFromId(entry); - if (numericId) { - return { input: entry, resolved: true, id: numericId }; - } - const stripped = normalizeTelegramAllowFromInput(entry); - if (!stripped || !params.credentialValue?.trim()) { - return { input: entry, resolved: false, id: null }; - } - const username = stripped.startsWith("@") ? stripped : `@${stripped}`; - const id = await lookupTelegramChatId({ - token: params.credentialValue, - chatId: username, - apiRoot: params.apiRoot, - proxyUrl: params.proxyUrl, - network: params.network, - }); - return { input: entry, resolved: Boolean(id), id }; - }), - ); -} - export async function promptTelegramAllowFromForAccount(params: { cfg: OpenClawConfig; prompter: WizardPrompter; @@ -82,30 +50,20 @@ export async function promptTelegramAllowFromForAccount(params: { const accountId = params.accountId ?? resolveDefaultTelegramAccountId(params.cfg); const resolved = resolveTelegramAccount({ cfg: params.cfg, accountId }); await params.prompter.note(TELEGRAM_USER_ID_HELP_LINES.join("\n"), "Telegram user id"); - if (!resolved.token?.trim()) { - await params.prompter.note( - "Telegram token missing; username lookup is unavailable.", - "Telegram", - ); - } const unique = await promptResolvedAllowFrom({ prompter: params.prompter, existing: resolved.config.allowFrom ?? [], - token: resolved.token, - message: "Telegram allowFrom (numeric sender id; @username resolves to id)", - placeholder: "@username", + message: "Telegram allowFrom (numeric sender id)", + placeholder: "123456789", label: "Telegram allowlist", parseInputs: splitSetupEntries, parseId: parseTelegramAllowFromId, invalidWithoutTokenNote: - "Telegram token missing; use numeric sender ids (usernames require a bot token).", - resolveEntries: async ({ entries, token }) => - resolveTelegramAllowFromEntries({ - credentialValue: token, - entries, - apiRoot: resolved.config.apiRoot, - proxyUrl: resolved.config.proxy, - network: resolved.config.network, + "Telegram allowFrom requires numeric sender ids. DM your bot first, then copy from.id from logs or getUpdates.", + resolveEntries: async ({ entries }) => + entries.map((entry) => { + const id = parseTelegramAllowFromId(entry); + return { input: entry, resolved: Boolean(id), id }; }), }); return patchChannelConfigForAccount({ diff --git a/extensions/telegram/src/setup-surface.test.ts b/extensions/telegram/src/setup-surface.test.ts index 1429f7f45e8..87582931e8c 100644 --- a/extensions/telegram/src/setup-surface.test.ts +++ b/extensions/telegram/src/setup-surface.test.ts @@ -1,13 +1,13 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup"; import { describe, expect, it, vi } from "vitest"; -import { resolveTelegramAllowFromEntries } from "./setup-core.js"; import { buildTelegramDmAccessWarningLines, ensureTelegramDefaultGroupMentionGate, shouldShowTelegramDmAccessWarning, telegramSetupDmPolicy, } from "./setup-surface.helpers.js"; +import { telegramSetupWizard } from "./setup-surface.js"; describe("ensureTelegramDefaultGroupMentionGate", () => { it('adds groups["*"].requireMention=true for fresh setups', async () => { @@ -167,45 +167,26 @@ describe("telegramSetupDmPolicy", () => { }); }); -describe("resolveTelegramAllowFromEntries", () => { - it("passes apiRoot through username lookups", async () => { +describe("telegramSetupWizard allowFrom", () => { + it("accepts numeric sender ids only", async () => { const globalFetch = vi.fn(async () => { throw new Error("global fetch should not be called"); }); - const fetchMock = vi.fn(async () => ({ - ok: true, - json: async () => ({ ok: true, result: { id: 12345 } }), - })); vi.stubGlobal("fetch", globalFetch); - const proxyFetch = vi.fn(); - const fetchModule = await import("./fetch.js"); - const proxyModule = await import("./proxy.js"); - const resolveTelegramFetch = vi.spyOn(fetchModule, "resolveTelegramFetch"); - const makeProxyFetch = vi.spyOn(proxyModule, "makeProxyFetch"); - makeProxyFetch.mockReturnValue(proxyFetch as unknown as typeof fetch); - resolveTelegramFetch.mockReturnValue(fetchMock as unknown as typeof fetch); try { - const resolved = await resolveTelegramAllowFromEntries({ + const resolved = await telegramSetupWizard.allowFrom?.resolveEntries({ + cfg: {}, + accountId: DEFAULT_ACCOUNT_ID, + credentialValues: { token: "tok" }, entries: ["@user"], - credentialValue: "tok", - apiRoot: "https://custom.telegram.test/root/", - proxyUrl: "http://127.0.0.1:8080", - network: { autoSelectFamily: false, dnsResultOrder: "ipv4first" }, }); - expect(resolved).toEqual([{ input: "@user", resolved: true, id: "12345" }]); - expect(makeProxyFetch).toHaveBeenCalledWith("http://127.0.0.1:8080"); - expect(resolveTelegramFetch).toHaveBeenCalledWith(proxyFetch, { - network: { autoSelectFamily: false, dnsResultOrder: "ipv4first" }, - }); - expect(fetchMock).toHaveBeenCalledWith( - "https://custom.telegram.test/root/bottok/getChat?chat_id=%40user", - undefined, - ); + expect(telegramSetupWizard.allowFrom?.message).toBe("Telegram allowFrom (numeric sender id)"); + expect(telegramSetupWizard.allowFrom?.placeholder).toBe("123456789"); + expect(resolved).toEqual([{ input: "@user", resolved: false, id: null }]); + expect(globalFetch).not.toHaveBeenCalled(); } finally { - makeProxyFetch.mockRestore(); - resolveTelegramFetch.mockRestore(); vi.unstubAllGlobals(); } }); diff --git a/extensions/telegram/src/setup-surface.ts b/extensions/telegram/src/setup-surface.ts index 76cd4784f5f..e33075db187 100644 --- a/extensions/telegram/src/setup-surface.ts +++ b/extensions/telegram/src/setup-surface.ts @@ -13,7 +13,6 @@ import { inspectTelegramAccount } from "./account-inspect.js"; import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; import { parseTelegramAllowFromId, - resolveTelegramAllowFromEntries, TELEGRAM_TOKEN_HELP_LINES, TELEGRAM_USER_ID_HELP_LINES, telegramSetupAdapter, @@ -79,18 +78,16 @@ export const telegramSetupWizard: ChannelSetupWizard = { allowFrom: createAllowFromSection({ helpTitle: "Telegram user id", helpLines: TELEGRAM_USER_ID_HELP_LINES, - credentialInputKey: "token", - message: "Telegram allowFrom (numeric sender id; @username resolves to id)", - placeholder: "@username", + message: "Telegram allowFrom (numeric sender id)", + placeholder: "123456789", invalidWithoutCredentialNote: - "Telegram token missing; use numeric sender ids (usernames require a bot token).", + "Telegram allowFrom requires numeric sender ids. DM your bot first, then copy from.id from logs or getUpdates.", parseInputs: splitSetupEntries, parseId: parseTelegramAllowFromId, - resolveEntries: async ({ cfg, accountId, credentialValues, entries }) => - resolveTelegramAllowFromEntries({ - credentialValue: credentialValues.token, - entries, - apiRoot: resolveTelegramAccount({ cfg, accountId }).config.apiRoot, + resolveEntries: async ({ entries }) => + entries.map((entry) => { + const id = parseTelegramAllowFromId(entry); + return { input: entry, resolved: Boolean(id), id }; }), apply: async ({ cfg, accountId, allowFrom }) => patchChannelConfigForAccount({