1+ import os
2+ import io
3+ import json
4+ import html
5+ import requests
6+ from flask import Flask , request , Response
7+
8+ TELEGRAM_CHAT_ID = - 4947069491
9+ TOKEN = os .environ .get ("TELEGRAM_BOT_TOKEN" )
10+ if not TOKEN :
11+ raise RuntimeError ("Set TELEGRAM_BOT_TOKEN env var" )
12+ TG_BASE = f"https://api.telegram.org/bot{ TOKEN } "
13+
14+ app = Flask (__name__ )
15+
16+ def _chunk (s : str , n : int = 3900 ):
17+ for i in range (0 , len (s ), n ):
18+ yield s [i :i + n ]
19+
20+ def send_text (text : str ):
21+ for part in _chunk (text ):
22+ r = requests .post (
23+ f"{ TG_BASE } /sendMessage" ,
24+ data = {
25+ "chat_id" : TELEGRAM_CHAT_ID ,
26+ "text" : f"<pre>{ html .escape (part )} </pre>" ,
27+ "parse_mode" : "HTML" ,
28+ "disable_web_page_preview" : True ,
29+ },
30+ timeout = 15 ,
31+ )
32+ r .raise_for_status ()
33+
34+ def send_document (fileobj , filename : str , caption : str = None , mime : str = None ):
35+ data = {"chat_id" : TELEGRAM_CHAT_ID }
36+ if caption :
37+ data ["caption" ] = caption [:1024 ]
38+ files = {"document" : (filename , fileobj , mime or "application/octet-stream" )}
39+ r = requests .post (f"{ TG_BASE } /sendDocument" , data = data , files = files , timeout = 120 )
40+ r .raise_for_status ()
41+
42+ @app .get ("/" )
43+ def root_ok ():
44+ return Response ("ok" , mimetype = "text/plain" )
45+
46+ @app .post ("/post" )
47+ def post_handler ():
48+ try :
49+ lines = []
50+ ctype = request .content_type or "-"
51+ lines .append (f"POST /post" )
52+ lines .append (f"Content-Type: { ctype } " )
53+
54+ if request .args :
55+ lines .append ("Query:" )
56+ lines .append (json .dumps (request .args .to_dict (flat = False ), ensure_ascii = False , indent = 2 ))
57+
58+ files_sent = 0
59+ body_summary = ""
60+
61+ if request .is_json :
62+ data = request .get_json (silent = True )
63+ if data is None :
64+ body_summary = (request .get_data (as_text = True ) or "" ).strip ()
65+ else :
66+ body_summary = json .dumps (data , ensure_ascii = False , indent = 2 )
67+
68+ elif request .mimetype == "application/x-www-form-urlencoded" :
69+ form = request .form .to_dict (flat = False )
70+ body_summary = json .dumps (form , ensure_ascii = False , indent = 2 )
71+
72+ elif request .mimetype and request .mimetype .startswith ("multipart/" ):
73+ form = request .form .to_dict (flat = False )
74+ if form :
75+ body_summary = json .dumps (form , ensure_ascii = False , indent = 2 )
76+ for key in request .files :
77+ for storage in request .files .getlist (key ):
78+ f = storage .stream
79+ f .seek (0 )
80+ caption = f"{ storage .filename or key } ({ storage .content_type or 'application/octet-stream' } )"
81+ send_document (f , storage .filename or key , caption = caption , mime = storage .content_type )
82+ files_sent += 1
83+
84+ else :
85+ raw = request .get_data ()
86+ try :
87+ txt = raw .decode ("utf-8" )
88+ if len (txt ) > 4000 :
89+ body_summary = txt [:4000 ] + "\n ...[truncated]"
90+ send_document (io .BytesIO (raw ), "payload.txt" , caption = "Raw payload" )
91+ else :
92+ body_summary = txt
93+ except UnicodeDecodeError :
94+ send_document (io .BytesIO (raw ), "payload.bin" , caption = "Binary payload" )
95+ body_summary = "(binary payload sent as document)"
96+
97+ if body_summary :
98+ lines .append ("Body:" )
99+ lines .append (body_summary )
100+
101+ send_text ("\n \n " .join (lines ))
102+ return Response ("ok" , mimetype = "text/plain" , status = 200 )
103+
104+ except requests .HTTPError :
105+ return Response ("ok" , mimetype = "text/plain" , status = 502 )
106+ except Exception :
107+ return Response ("ok" , mimetype = "text/plain" , status = 500 )
108+
109+ if __name__ == "__main__" :
110+ app .run (host = "0.0.0.0" , port = 8080 )
0 commit comments