- 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
71 lines
2.5 KiB
JavaScript
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);
|