Files
Arah2/bot/scripts/set-webhook.mjs
T
araharah-executor df3b7d65c1 feat(02-03): Worker entry — webhook route + /api/session security gate + deploy plumbing (D-11, D-14, D-16, D-17)
- src/webhook.ts: routes exactly /telegram/webhook (grammY cloudflare-mod
  adapter, constant-time secret-token auth against env.WEBHOOK_SECRET) and
  POST /api/session (validateInitData → 401 category-only rejections →
  mintSession one-time token; single mint path, no extra branch — T-02-01/02/06)
- D-14: the only log statement is '[initdata] rejected: <category>' — no
  payload, ids, or timestamps
- scripts/set-webhook.mjs: setWebhook with secret_token + allowed_updates
  [message], secrets read from gitignored .dev.vars, token never echoed
- bot deploy script chains wrangler deploy + set-webhook; wrangler.jsonc
  gains workers_dev (webhook URL target); KV id stays placeholder for the
  deploy checkpoint
- verified: 27/27 tests, typecheck clean, wrangler deploy --dry-run exit 0
2026-10-22 11:49:43 +08:00

71 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
/*
* set-webhook.mjs — one-time setWebhook registration (D-16, D-17).
* -----------------------------------------------------------------
* Points Telegram at the Worker's /telegram/webhook route and arms the
* secret-token channel: the `secret_token` value sent here is the one
* Telegram echoes back in X-Telegram-Bot-Api-Secret-Token on every update,
* which the Worker's webhook adapter constant-time-compares against
* env.WEBHOOK_SECRET (T-02-03).
*
* Inputs come from bot/.dev.vars (gitignored, D-15): BOT_TOKEN,
* WEBHOOK_URL, WEBHOOK_SECRET. The bot token is never echoed — on failure
* only the API's error_code/description are printed (T-02-04).
* Exit 0 only when Telegram answers ok:true.
*/
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
function readDevVars() {
const devVarsPath = path.join(fileURLToPath(new URL(import.meta.url)), "..", "..", ".dev.vars");
let raw = "";
try {
raw = readFileSync(devVarsPath, "utf8");
} catch {
return {};
}
const vars = {};
for (const line of raw.split("\n")) {
const trimmed = line.trim();
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
const eq = trimmed.indexOf("=");
if (eq === -1) continue;
vars[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
}
return vars;
}
const devVars = readDevVars();
const token = process.env.BOT_TOKEN ?? devVars.BOT_TOKEN;
const webhookUrl = process.env.WEBHOOK_URL ?? devVars.WEBHOOK_URL;
const secret = process.env.WEBHOOK_SECRET ?? devVars.WEBHOOK_SECRET;
const missing = ["BOT_TOKEN", "WEBHOOK_URL", "WEBHOOK_SECRET"].filter(
(name) => !{ BOT_TOKEN: token, WEBHOOK_URL: webhookUrl, WEBHOOK_SECRET: secret }[name],
);
if (missing.length > 0) {
console.error(`Missing ${missing.join(", ")} — set them in bot/.dev.vars (see .dev.vars.example; never commit).`);
process.exit(1);
}
const payload = {
url: webhookUrl,
secret_token: secret,
allowed_updates: ["message"],
};
const res = await fetch(`https://api.telegram.org/bot${token}/setWebhook`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(payload),
});
const body = await res.json();
if (!body.ok) {
console.error(`setWebhook failed: ${body.error_code ?? "?"} ${body.description ?? "unknown error"}`);
process.exit(1);
}
console.log(`setWebhook ok:true — updates will be delivered to the configured URL with the secret-token header.`);
process.exit(0);