File size: 2,057 Bytes
2e658e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const METHODS = new Set(["sendMessage", "answerCallbackQuery", "editMessageText"]);
const buckets = new Map();

async function hexHmac(secret, body) {
  const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), {name:"HMAC", hash:"SHA-256"}, false, ["sign"]);
  const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(body));
  return [...new Uint8Array(sig)].map(x => x.toString(16).padStart(2, "0")).join("");
}

export default {
  async fetch(request, env) {
    if (request.method !== "POST") return new Response("method not allowed", {status:405});
    const ip = request.headers.get("CF-Connecting-IP") || "unknown";
    const now = Date.now(); const recent = (buckets.get(ip) || []).filter(t => now - t < 60000);
    if (recent.length >= 30) return new Response("rate limited", {status:429});
    recent.push(now); buckets.set(ip, recent);
    const body = await request.text();
    const supplied = request.headers.get("X-Relay-Signature") || "";
    if (!supplied || !(await crypto.subtle.verify("HMAC", await crypto.subtle.importKey("raw", new TextEncoder().encode(env.TELEGRAM_RELAY_SECRET || ""), {name:"HMAC", hash:"SHA-256"}, false, ["verify"]), hexToBytes(supplied), new TextEncoder().encode(body)))) return new Response("unauthorized", {status:401});
    let input; try { input = JSON.parse(body); } catch { return new Response("bad request", {status:400}); }
    if (!METHODS.has(input.method) || !input.payload || typeof input.payload !== "object") return new Response("method not allowed", {status:403});
    const response = await fetch(`https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/${input.method}`, {method:"POST", headers:{"content-type":"application/json"}, body:JSON.stringify(input.payload)});
    return new Response(await response.text(), {status:response.status, headers:{"content-type":"application/json"}});
  }
};

function hexToBytes(hex) { const out = new Uint8Array(hex.length / 2); for (let i=0;i<out.length;i++) out[i] = parseInt(hex.substr(i*2,2),16); return out; }