JerryCoder commited on
Commit
b79792a
·
verified ·
1 Parent(s): 5e04af4

Create bot.py

Browse files
Files changed (1) hide show
  1. bot.py +195 -0
bot.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import sys
4
+ import zipfile
5
+ import base64
6
+ import random
7
+ import shutil
8
+ import subprocess
9
+ import tempfile
10
+ from pathlib import Path
11
+
12
+ from fastapi import FastAPI, Request
13
+ from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
14
+ from telegram.ext import (
15
+ Application,
16
+ CommandHandler,
17
+ MessageHandler,
18
+ filters,
19
+ ContextTypes,
20
+ )
21
+
22
+ from motor.motor_asyncio import AsyncIOMotorClient
23
+ import uvicorn
24
+ from config import BOT_TOKEN, ADMIN_ID, MONGO_URI, DB_NAME
25
+
26
+ # -------------------- MongoDB Setup --------------------
27
+ mongo_client = AsyncIOMotorClient(MONGO_URI)
28
+ db = mongo_client[DB_NAME]
29
+ users_col = db["users"]
30
+ bans_col = db["banned_users"]
31
+ stats_col = db["stats"]
32
+
33
+ async def init_stats():
34
+ if not await stats_col.find_one({"_id": "encryption_count"}):
35
+ await stats_col.insert_one({"_id": "encryption_count", "count": 0})
36
+
37
+ # -------------------- Helpers --------------------
38
+ def make_zip_bytes(filename: str, content: bytes) -> bytes:
39
+ bio = io.BytesIO()
40
+ with zipfile.ZipFile(bio, "w", compression=zipfile.ZIP_DEFLATED) as zf:
41
+ zf.writestr(filename, content)
42
+ return bio.getvalue()
43
+
44
+ def rand_bytes(n):
45
+ return os.urandom(n)
46
+
47
+ def bytes_to_c_array_literal(b: bytes) -> str:
48
+ return ",".join(str(x) for x in b)
49
+
50
+ def xor_string(s: str, key: int = None) -> str:
51
+ if key is None:
52
+ key = random.randint(1, 255)
53
+ arr = [ord(c) ^ key for c in s]
54
+ return f"(lambda s:''.join(chr(B^{key}) for B in s))([{','.join(str(x) for x in arr)}])"
55
+
56
+ def generate_junk_data(min_kb=50, max_kb=70):
57
+ junk_size = random.randint(min_kb * 1024, max_kb * 1024)
58
+ chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_()-./,;:!?"
59
+ return ''.join(random.choice(chars) for _ in range(junk_size))
60
+
61
+ # -------------------- C Template --------------------
62
+ C_TEMPLATE = """/*KEY_BYTES*/"""
63
+ SETUP_PY = """# Your setup.py content"""
64
+
65
+ def compile_c_extension(build_dir: Path):
66
+ (build_dir / "setup.py").write_text(SETUP_PY)
67
+ proc = subprocess.run(
68
+ [sys.executable, "setup.py", "build_ext", "--inplace"],
69
+ cwd=str(build_dir),
70
+ stdout=subprocess.PIPE,
71
+ stderr=subprocess.STDOUT,
72
+ timeout=30,
73
+ )
74
+ candidates = list(build_dir.glob("aes_helper*.so")) + list(build_dir.glob("build/lib.*/*.so"))
75
+ if not candidates:
76
+ raise RuntimeError("Compile fail:\n" + proc.stdout.decode())
77
+ return candidates[0]
78
+
79
+ def build_wrapper(j_b64, so_b64, so_filename):
80
+ lines = [
81
+ "wulcan = '.WulcanPy'",
82
+ "import os as O, sys as S, base64 as B, tempfile as T",
83
+ f"WL='{j_b64}'",
84
+ f"M={repr(so_b64)}",
85
+ f"D=O.path.join(T.gettempdir(),{xor_string('ninja_tmp')});O.makedirs(D,exist_ok=True)",
86
+ f"P=O.path.join(D,{xor_string(so_filename)})",
87
+ "open(P,'wb').write(B.b64decode(M))",
88
+ "import importlib.machinery as L, importlib.util as U",
89
+ "loader=L.ExtensionFileLoader('aes_helper',P);spec=U.spec_from_loader(loader.name,loader);mod=U.module_from_spec(spec);loader.exec_module(mod)",
90
+ "import sys, io, zipfile, runpy",
91
+ "try:",
92
+ "\tc=B.b64decode(WL);z=mod.decrypt(c)",
93
+ "\tt=T.mkdtemp(prefix='nin_');zipfile.ZipFile(io.BytesIO(z)).extractall(t)",
94
+ "\tS.path.insert(0,t)",
95
+ "\te=[f for f in O.listdir(t) if f.endswith('.py')][0]",
96
+ "\tep=O.path.join(t,e)",
97
+ "\tS.argv=[ep]+S.argv[1:]",
98
+ "\trunpy.run_path(ep,run_name='__main__')",
99
+ "except Exception as E: print('ninja_error',E)",
100
+ "finally: O.remove(P) if O.path.exists(P) else None",
101
+ f"JUNK={repr(generate_junk_data())}"
102
+ ]
103
+ return "\n".join(lines)
104
+
105
+ # -------------------- File Processing --------------------
106
+ async def process_file(input_file: Path, update: Update, context: ContextTypes.DEFAULT_TYPE):
107
+ tmpdir = Path(tempfile.mkdtemp())
108
+ tmp_file = tmpdir / input_file.name
109
+ tmp_file.write_bytes(input_file.read_bytes())
110
+ py_bytes = tmp_file.read_bytes()
111
+ zip_b = make_zip_bytes(input_file.name, py_bytes)
112
+ key, iv = rand_bytes(32), rand_bytes(16)
113
+ c_src = C_TEMPLATE.replace("/*KEY_BYTES*/", bytes_to_c_array_literal(key)).replace("/*IV_BYTES*/", bytes_to_c_array_literal(iv))
114
+ (tmpdir / "aes_helper.c").write_text(c_src)
115
+ so_path = compile_c_extension(tmpdir)
116
+ import importlib.util
117
+ spec = importlib.util.spec_from_file_location("aes_helper", so_path)
118
+ mod = importlib.util.module_from_spec(spec)
119
+ spec.loader.exec_module(mod)
120
+ cipher = mod.encrypt(zip_b)
121
+ cipher_b64 = base64.b64encode(cipher).decode()
122
+ so_b64 = base64.b64encode(so_path.read_bytes()).decode()
123
+ wrapper = build_wrapper(cipher_b64, so_b64, so_path.name)
124
+ out_name = input_file.stem + "_enc.py"
125
+ out_path = tmpdir / out_name
126
+ out_path.write_text(wrapper)
127
+ await context.bot.send_document(chat_id=update.effective_chat.id, document=open(out_path, "rb"), filename=out_name)
128
+ await stats_col.update_one({"_id": "encryption_count"}, {"$inc": {"count": 1}})
129
+ shutil.rmtree(tmpdir, ignore_errors=True)
130
+
131
+ # -------------------- Handlers --------------------
132
+ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
133
+ user = update.effective_user
134
+ if not await users_col.find_one({"user_id": user.id}):
135
+ await users_col.insert_one({"user_id": user.id, "name": user.full_name,
136
+ "username": user.username or "None",
137
+ "language": user.language_code or "Unknown"})
138
+ keyboard = [[InlineKeyboardButton("▶ Join Channel", url="https://t.me/kuttuxd17")]]
139
+ await update.message.reply_text("Welcome to Secure File Encryptor Bot!", reply_markup=InlineKeyboardMarkup(keyboard))
140
+
141
+ async def encode(update: Update, context: ContextTypes.DEFAULT_TYPE):
142
+ user = update.effective_user
143
+ if await bans_col.find_one({"user_id": user.id}):
144
+ await update.message.reply_text("You are banned.")
145
+ return
146
+ await update.message.reply_text("Please upload a .py file.")
147
+
148
+ async def handle_document(update: Update, context: ContextTypes.DEFAULT_TYPE):
149
+ document = update.message.document
150
+ tmpdir = Path(tempfile.mkdtemp())
151
+ tmp_path = tmpdir / document.file_name
152
+ file = await document.get_file()
153
+ await file.download_to_drive(str(tmp_path))
154
+ await process_file(tmp_path, update, context)
155
+
156
+ # -------------------- Admin Commands --------------------
157
+ async def total_users(update: Update, context: ContextTypes.DEFAULT_TYPE):
158
+ if update.effective_user.id != ADMIN_ID: return
159
+ count = await users_col.count_documents({})
160
+ await update.message.reply_text(f"Total users: {count}")
161
+
162
+ async def total_enc(update: Update, context: ContextTypes.DEFAULT_TYPE):
163
+ if update.effective_user.id != ADMIN_ID: return
164
+ stats = await stats_col.find_one({"_id": "encryption_count"})
165
+ await update.message.reply_text(f"Total encryptions: {stats['count'] if stats else 0}")
166
+
167
+ # -------------------- FastAPI App --------------------
168
+ app = FastAPI()
169
+ bot_app = Application.builder().token(BOT_TOKEN).build()
170
+
171
+ # Register Handlers
172
+ bot_app.add_handler(CommandHandler("start", start))
173
+ bot_app.add_handler(CommandHandler("encode", encode))
174
+ bot_app.add_handler(MessageHandler(filters.Document.ALL, handle_document))
175
+ bot_app.add_handler(CommandHandler("totalusers", total_users))
176
+ bot_app.add_handler(CommandHandler("totalenc", total_enc))
177
+
178
+ @app.post("/webhook")
179
+ async def webhook_endpoint(request: Request):
180
+ update_data = await request.json()
181
+ update = Update.update_from_dict(update_data)
182
+ await bot_app.process_update(update)
183
+ return {"ok": True}
184
+
185
+ # -------------------- Run --------------------
186
+ if __name__ == "__main__":
187
+ import asyncio
188
+
189
+ async def main():
190
+ await init_stats()
191
+ await bot_app.initialize()
192
+ await bot_app.start()
193
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
194
+
195
+ asyncio.run(main())