akborana4 commited on
Commit
227fac1
·
verified ·
1 Parent(s): b23f546

Major update bash install etc

Browse files
Files changed (1) hide show
  1. main.py +204 -46
main.py CHANGED
@@ -1,9 +1,9 @@
1
  """
2
- Master Bot (Telethon) - Eval Userbot Edition
3
- - Users upload a valid .session file to register an assistant.
4
- - Assistant responds to '.val', '!val', or '/val' with Python evaluation.
5
- - Eval is STRICTLY limited to outgoing messages (the session owner).
6
- - Logs sent to LOG_CHANNEL_ID on silent mode errors.
7
  """
8
 
9
  import os
@@ -15,36 +15,39 @@ import inspect
15
  import sys
16
  import traceback
17
  import json
 
18
  from io import StringIO, BytesIO
19
  from datetime import datetime
20
  from typing import Dict, Any, Optional
21
 
 
22
  from telethon import TelegramClient, events, Button
23
  from telethon.utils import get_display_name
24
 
25
- # Used for Formatting Eval Code, if installed
26
  try:
27
  import black
28
  except ImportError:
29
  black = None
30
 
31
  # ---------------- CONFIG - EDIT THESE ----------------
32
- API_ID = 22138159 # <-- Replace with your API_ID
33
- API_HASH = "3fe4592e4cad72f366b6c564505f2d57" # <-- Replace with your API_HASH
34
 
35
  MASTER_BOT_SESSION = "master.session"
36
  DB_PATH = "masterbot.db"
37
  SESSIONS_DIR = "sessions"
 
38
 
39
  SUPER_ADMIN_ID = 7205748624
40
  LOG_CHANNEL_ID = -1002524453831
41
 
42
- CLIENT_IDLE_TIMEOUT = 60 * 60 # 1 hour
43
  CLEANUP_INTERVAL = 15 * 60
44
  MAX_ACTIVE_CLIENTS = 60
45
  # ---------------- END CONFIG ----------------
46
 
47
  os.makedirs(SESSIONS_DIR, exist_ok=True)
 
48
  logging.basicConfig(level=logging.INFO)
49
  logger = logging.getLogger("masterbot")
50
 
@@ -129,7 +132,7 @@ def init_db():
129
  bot_username TEXT NOT NULL UNIQUE,
130
  token_encrypted BLOB NOT NULL,
131
  active INTEGER NOT NULL DEFAULT 1,
132
- reply_text TEXT, -- Kept for legacy DB compatibility
133
  created_at TEXT NOT NULL
134
  );
135
  """)
@@ -140,6 +143,14 @@ def init_db():
140
  banned_at TEXT
141
  );
142
  """)
 
 
 
 
 
 
 
 
143
  conn.commit()
144
  return conn
145
 
@@ -194,6 +205,22 @@ def db_is_banned(user_id: int) -> bool:
194
  cur.execute("SELECT 1 FROM bans WHERE user_id = ?", (user_id,))
195
  return cur.fetchone() is not None
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  def session_path_for_username(username: str) -> str:
198
  safe = username.replace("@", "")
199
  return os.path.join(SESSIONS_DIR, f"{safe}.session")
@@ -207,7 +234,7 @@ async def send_to_log_channel(text: str, file=None, parse_mode=None):
207
  except Exception:
208
  logger.exception("Failed to send log to channel")
209
 
210
- # ---------------- Assistant lifecycle & EVAL HANDLER ----------------
211
  async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
212
  sess_path = session_path_for_username(bot_username)
213
  if not os.path.exists(sess_path):
@@ -220,19 +247,30 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
220
  if not await client.is_user_authorized():
221
  await client.disconnect()
222
  return False
 
 
223
  except Exception as e:
224
  logger.exception("Failed to start assistant client for %s: %s", bot_username, e)
225
  return False
226
 
227
- # Eval Handler - STRICTLY outgoing to prevent RCE by strangers
 
 
 
 
 
 
 
 
228
  @client.on(events.NewMessage(pattern=r"^[.\/!]val(?:\s|$)"))
229
  async def eval_handler(event):
 
 
230
  try:
231
  cmd = event.text.split(maxsplit=1)[1]
232
  except IndexError:
233
  return await eor(event, "Please provide code to evaluate.")
234
-
235
- # Update last used state
236
  async with assistant_lock:
237
  if bot_username in assistant_clients:
238
  assistant_clients[bot_username]["last_used"] = time.time()
@@ -243,11 +281,10 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
243
 
244
  async def get_():
245
  try:
246
- cm = cmd.split(maxsplit=1)[1]
247
  except IndexError:
248
  await eor(event, "->> Wrong Format <<-")
249
- cm = None
250
- return cm
251
 
252
  if spli[0] in ["-s", "--silent"]:
253
  await event.delete()
@@ -260,10 +297,8 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
260
  elif spli[0] in ["-ga", "--args"]:
261
  mode = "g-args"
262
 
263
- if mode:
264
- cmd = await get_()
265
- if not cmd:
266
- return
267
 
268
  if not mode == "silent" and not xx:
269
  xx = await eor(event, "Running...")
@@ -271,12 +306,10 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
271
  if black:
272
  try:
273
  cmd = black.format_str(cmd, mode=black.Mode())
274
- except BaseException:
275
- pass
276
 
277
  reply_to_id = event.reply_to_msg_id or event
278
- old_stderr = sys.stderr
279
- old_stdout = sys.stdout
280
  redirected_output = sys.stdout = StringIO()
281
  redirected_error = sys.stderr = StringIO()
282
  stdout, stderr, exc, timeg = None, None, None, None
@@ -291,8 +324,7 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
291
  tima = time.time() - tima
292
  stdout = redirected_output.getvalue()
293
  stderr = redirected_error.getvalue()
294
- sys.stdout = old_stdout
295
- sys.stderr = old_stderr
296
 
297
  if value:
298
  try:
@@ -321,31 +353,158 @@ async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
321
  tmt = tima * 1000
322
  timef = time_formatter(tmt)
323
  timeform = timef if not timef == "0s" else f"{tmt:.3f}ms"
324
- final_output = "__►__ **EVAL** (__in {}__)\n```python\n{}``` \n\n __►__ **OUTPUT**: \n```\n{}``` \n".format(
325
- timeform,
326
- cmd,
327
- evaluation,
328
- )
329
 
330
  if len(final_output) > 4096:
331
  final_output = evaluation
332
  with BytesIO(str.encode(final_output)) as out_file:
333
  out_file.name = "eval.txt"
334
- await client.send_file(
335
- event.chat_id,
336
- out_file,
337
- force_document=True,
338
- allow_cache=False,
339
- caption=f"```{cmd}```" if len(cmd) < 998 else None,
340
- reply_to=reply_to_id,
341
- )
342
- if xx:
343
- return await xx.delete()
344
  return
345
 
346
- if xx:
347
- await eor(xx, final_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
 
349
  async with assistant_lock:
350
  if len(assistant_clients) >= MAX_ACTIVE_CLIENTS:
351
  await client.disconnect()
@@ -444,7 +603,7 @@ async def generic_handler(event):
444
 
445
  if success:
446
  db_set_active(bot_username, True)
447
- await msg.edit(f"✅ Registered {bot_username} successfully!\nYou can now use `.val` or `!val` from that account to run code.")
448
  await send_to_log_channel(f"Master: User {uid} registered {bot_username}.")
449
  else:
450
  await msg.edit("Session valid, but failed to start client.")
@@ -529,4 +688,3 @@ async def main():
529
 
530
  if __name__ == "__main__":
531
  asyncio.run(main())
532
-
 
1
  """
2
+ Master Bot (Telethon) - Eval & Plugin Userbot Edition
3
+ - Upload a .session file to register an assistant.
4
+ - Assistants respond to .val, .bash, /install, /promote, /demote, /help
5
+ - Commands are restricted to the owner, the userbot account itself, and promoted users.
6
+ - Dynamic plugin loading via /install.
7
  """
8
 
9
  import os
 
15
  import sys
16
  import traceback
17
  import json
18
+ import importlib.util
19
  from io import StringIO, BytesIO
20
  from datetime import datetime
21
  from typing import Dict, Any, Optional
22
 
23
+ import telethon
24
  from telethon import TelegramClient, events, Button
25
  from telethon.utils import get_display_name
26
 
 
27
  try:
28
  import black
29
  except ImportError:
30
  black = None
31
 
32
  # ---------------- CONFIG - EDIT THESE ----------------
33
+ API_ID = 22138159
34
+ API_HASH = "3fe4592e4cad72f366b6c564505f2d57"
35
 
36
  MASTER_BOT_SESSION = "master.session"
37
  DB_PATH = "masterbot.db"
38
  SESSIONS_DIR = "sessions"
39
+ PLUGINS_DIR = "plugins"
40
 
41
  SUPER_ADMIN_ID = 7205748624
42
  LOG_CHANNEL_ID = -1002524453831
43
 
44
+ CLIENT_IDLE_TIMEOUT = 60 * 60
45
  CLEANUP_INTERVAL = 15 * 60
46
  MAX_ACTIVE_CLIENTS = 60
47
  # ---------------- END CONFIG ----------------
48
 
49
  os.makedirs(SESSIONS_DIR, exist_ok=True)
50
+ os.makedirs(PLUGINS_DIR, exist_ok=True)
51
  logging.basicConfig(level=logging.INFO)
52
  logger = logging.getLogger("masterbot")
53
 
 
132
  bot_username TEXT NOT NULL UNIQUE,
133
  token_encrypted BLOB NOT NULL,
134
  active INTEGER NOT NULL DEFAULT 1,
135
+ reply_text TEXT,
136
  created_at TEXT NOT NULL
137
  );
138
  """)
 
143
  banned_at TEXT
144
  );
145
  """)
146
+ # New table for promoted users
147
+ cur.execute("""
148
+ CREATE TABLE IF NOT EXISTS sudoers (
149
+ bot_username TEXT NOT NULL,
150
+ user_id INTEGER NOT NULL,
151
+ UNIQUE(bot_username, user_id)
152
+ );
153
+ """)
154
  conn.commit()
155
  return conn
156
 
 
205
  cur.execute("SELECT 1 FROM bans WHERE user_id = ?", (user_id,))
206
  return cur.fetchone() is not None
207
 
208
+ # Sudo Utilities
209
+ def db_add_sudo(bot_username: str, user_id: int):
210
+ cur = db.cursor()
211
+ cur.execute("INSERT OR IGNORE INTO sudoers (bot_username, user_id) VALUES (?, ?)", (bot_username, user_id))
212
+ db.commit()
213
+
214
+ def db_remove_sudo(bot_username: str, user_id: int):
215
+ cur = db.cursor()
216
+ cur.execute("DELETE FROM sudoers WHERE bot_username = ? AND user_id = ?", (bot_username, user_id))
217
+ db.commit()
218
+
219
+ def db_get_sudos(bot_username: str):
220
+ cur = db.cursor()
221
+ cur.execute("SELECT user_id FROM sudoers WHERE bot_username = ?", (bot_username,))
222
+ return [row[0] for row in cur.fetchall()]
223
+
224
  def session_path_for_username(username: str) -> str:
225
  safe = username.replace("@", "")
226
  return os.path.join(SESSIONS_DIR, f"{safe}.session")
 
234
  except Exception:
235
  logger.exception("Failed to send log to channel")
236
 
237
+ # ---------------- Assistant lifecycle & COMMAND HANDLERS ----------------
238
  async def create_and_start_assistant(bot_username: str, owner_id: int) -> bool:
239
  sess_path = session_path_for_username(bot_username)
240
  if not os.path.exists(sess_path):
 
247
  if not await client.is_user_authorized():
248
  await client.disconnect()
249
  return False
250
+ me = await client.get_me()
251
+ bot_id = me.id
252
  except Exception as e:
253
  logger.exception("Failed to start assistant client for %s: %s", bot_username, e)
254
  return False
255
 
256
+ # Authorization check function
257
+ async def is_auth(event):
258
+ sender_id = event.sender_id
259
+ if sender_id == owner_id: return True # Master owner
260
+ if sender_id == bot_id: return True # The userbot itself
261
+ if sender_id in db_get_sudos(bot_username): return True # Promoted users
262
+ return False
263
+
264
+ # 1. VAL SCRIPT (Eval)
265
  @client.on(events.NewMessage(pattern=r"^[.\/!]val(?:\s|$)"))
266
  async def eval_handler(event):
267
+ if not await is_auth(event): return
268
+
269
  try:
270
  cmd = event.text.split(maxsplit=1)[1]
271
  except IndexError:
272
  return await eor(event, "Please provide code to evaluate.")
273
+
 
274
  async with assistant_lock:
275
  if bot_username in assistant_clients:
276
  assistant_clients[bot_username]["last_used"] = time.time()
 
281
 
282
  async def get_():
283
  try:
284
+ return cmd.split(maxsplit=1)[1]
285
  except IndexError:
286
  await eor(event, "->> Wrong Format <<-")
287
+ return None
 
288
 
289
  if spli[0] in ["-s", "--silent"]:
290
  await event.delete()
 
297
  elif spli[0] in ["-ga", "--args"]:
298
  mode = "g-args"
299
 
300
+ if mode: cmd = await get_()
301
+ if not cmd: return
 
 
302
 
303
  if not mode == "silent" and not xx:
304
  xx = await eor(event, "Running...")
 
306
  if black:
307
  try:
308
  cmd = black.format_str(cmd, mode=black.Mode())
309
+ except BaseException: pass
 
310
 
311
  reply_to_id = event.reply_to_msg_id or event
312
+ old_stderr, old_stdout = sys.stderr, sys.stdout
 
313
  redirected_output = sys.stdout = StringIO()
314
  redirected_error = sys.stderr = StringIO()
315
  stdout, stderr, exc, timeg = None, None, None, None
 
324
  tima = time.time() - tima
325
  stdout = redirected_output.getvalue()
326
  stderr = redirected_error.getvalue()
327
+ sys.stdout, sys.stderr = old_stdout, old_stderr
 
328
 
329
  if value:
330
  try:
 
353
  tmt = tima * 1000
354
  timef = time_formatter(tmt)
355
  timeform = timef if not timef == "0s" else f"{tmt:.3f}ms"
356
+ final_output = "__►__ **EVAL** (__in {}__)\n```python\n{}``` \n\n __►__ **OUTPUT**: \n```\n{}``` \n".format(timeform, cmd, evaluation)
 
 
 
 
357
 
358
  if len(final_output) > 4096:
359
  final_output = evaluation
360
  with BytesIO(str.encode(final_output)) as out_file:
361
  out_file.name = "eval.txt"
362
+ await client.send_file(event.chat_id, out_file, force_document=True, allow_cache=False, caption=f"```{cmd}```" if len(cmd) < 998 else None, reply_to=reply_to_id)
363
+ if xx: return await xx.delete()
 
 
 
 
 
 
 
 
364
  return
365
 
366
+ if xx: await eor(xx, final_output)
367
+
368
+ # 2. BASH SCRIPT (Shell Execution)
369
+ @client.on(events.NewMessage(pattern=r"^[.\/!]bash(?:\s|$)"))
370
+ async def bash_handler(event):
371
+ if not await is_auth(event): return
372
+
373
+ try:
374
+ cmd = event.text.split(maxsplit=1)[1]
375
+ except IndexError:
376
+ return await eor(event, "Please provide a shell command to execute.")
377
+
378
+ xx = await eor(event, "`Executing bash command...`")
379
+
380
+ try:
381
+ process = await asyncio.create_subprocess_shell(
382
+ cmd,
383
+ stdout=asyncio.subprocess.PIPE,
384
+ stderr=asyncio.subprocess.PIPE
385
+ )
386
+ stdout, stderr = await process.communicate()
387
+
388
+ output = stdout.decode().strip() or stderr.decode().strip() or "Command executed successfully with no output."
389
+
390
+ final_output = f"**► BASH**\n```bash\n{cmd}```\n\n**► OUTPUT**\n```\n{output}```"
391
+
392
+ if len(final_output) > 4000:
393
+ with BytesIO(output.encode()) as out_file:
394
+ out_file.name = "bash_output.txt"
395
+ await client.send_file(event.chat_id, out_file, caption=f"`{cmd}`")
396
+ await xx.delete()
397
+ else:
398
+ await eor(xx, final_output)
399
+
400
+ except Exception as e:
401
+ err = traceback.format_exc()
402
+ await eor(xx, f"**► BASH ERROR**\n```bash\n{cmd}```\n\n**► ERROR**\n```\n{err}```")
403
+ await send_to_log_channel(f"Bash Error on {bot_username}: {str(e)}")
404
+
405
+ # 3. INSTALL PLUGIN
406
+ @client.on(events.NewMessage(pattern=r"^[.\/!]install$"))
407
+ async def install_handler(event):
408
+ if not await is_auth(event): return
409
+
410
+ if not event.is_reply:
411
+ example = (
412
+ "**How to use /install:**\n\n"
413
+ "1. Reply to a `.py` file containing Telethon code.\n"
414
+ "2. The file will be downloaded and its code loaded dynamically.\n\n"
415
+ "**Example Plugin:**\n"
416
+ "```python\n"
417
+ "@client.on(events.NewMessage(pattern='/ping'))\n"
418
+ "async def ping(event):\n"
419
+ " await event.reply('Pong!')\n"
420
+ "```"
421
+ )
422
+ return await eor(event, example)
423
+
424
+ reply = await event.get_reply_message()
425
+ if not reply.file or not reply.file.name.endswith('.py'):
426
+ return await eor(event, "Please reply to a valid `.py` Python script.")
427
+
428
+ xx = await eor(event, "`Installing plugin...`")
429
+
430
+ plugin_name = reply.file.name
431
+ bot_plugin_dir = os.path.join(PLUGINS_DIR, bot_username.replace("@", ""))
432
+ os.makedirs(bot_plugin_dir, exist_ok=True)
433
+
434
+ file_path = os.path.join(bot_plugin_dir, plugin_name)
435
+ await reply.download_media(file=file_path)
436
+
437
+ try:
438
+ # We inject 'client', 'events', and 'telethon' into the script's global namespace
439
+ # so the decorators in the raw script will attach directly to this specific assistant.
440
+ with open(file_path, "r", encoding="utf-8") as f:
441
+ code_str = f.read()
442
+
443
+ exec_globals = {
444
+ "client": client,
445
+ "events": events,
446
+ "telethon": telethon,
447
+ "asyncio": asyncio,
448
+ "os": os,
449
+ "sys": sys
450
+ }
451
+ exec(code_str, exec_globals)
452
+ await eor(xx, f"✅ **Successfully installed module:** `{plugin_name}`")
453
+ except Exception as e:
454
+ err = traceback.format_exc()
455
+ await eor(xx, f"❌ **Failed to install {plugin_name}**\n\n```python\n{err}```")
456
+ if os.path.exists(file_path): os.remove(file_path)
457
+
458
+ # 4. PROMOTE / DEMOTE
459
+ @client.on(events.NewMessage(pattern=r"^[.\/!]promote(?:\s|$)"))
460
+ async def promote_handler(event):
461
+ if event.sender_id != owner_id and event.sender_id != bot_id:
462
+ return await eor(event, "Only the owner can promote users.")
463
+
464
+ try:
465
+ target = event.text.split(maxsplit=1)[1]
466
+ entity = await client.get_entity(target)
467
+ db_add_sudo(bot_username, entity.id)
468
+ await eor(event, f"✅ Successfully promoted `{entity.first_name}` to sudo.")
469
+ except IndexError:
470
+ await eor(event, "Provide a username or user ID.")
471
+ except Exception as e:
472
+ await eor(event, f"Error: {str(e)}")
473
+
474
+ @client.on(events.NewMessage(pattern=r"^[.\/!]demote(?:\s|$)"))
475
+ async def demote_handler(event):
476
+ if event.sender_id != owner_id and event.sender_id != bot_id:
477
+ return await eor(event, "Only the owner can demote users.")
478
+
479
+ try:
480
+ target = event.text.split(maxsplit=1)[1]
481
+ entity = await client.get_entity(target)
482
+ db_remove_sudo(bot_username, entity.id)
483
+ await eor(event, f"❌ Successfully demoted `{entity.first_name}`.")
484
+ except IndexError:
485
+ await eor(event, "Provide a username or user ID.")
486
+ except Exception as e:
487
+ await eor(event, f"Error: {str(e)}")
488
+
489
+ # 5. HELP COMMAND
490
+ @client.on(events.NewMessage(pattern=r"^[.\/!]help$"))
491
+ async def help_handler(event):
492
+ if not await is_auth(event): return
493
+
494
+ help_text = (
495
+ f"🤖 **{bot_username} Assistant Help Menu**\n\n"
496
+ "**Core Commands:**\n"
497
+ "🔹 `.val <code>` - Evaluate Python code.\n"
498
+ "🔹 `.bash <code>` - Execute shell/terminal commands.\n"
499
+ "🔹 `/install` - Reply to a `.py` file to load custom code.\n\n"
500
+ "**Admin Commands (Owner Only):**\n"
501
+ "🔹 `/promote <id/username>` - Allow a user to use this bot's commands.\n"
502
+ "🔹 `/demote <id/username>` - Revoke user's access.\n\n"
503
+ "*(Note: Telegram user accounts cannot send inline buttons, which is why this is a text menu!)*"
504
+ )
505
+ await eor(event, help_text)
506
 
507
+ # --- Start Assistant Registration ---
508
  async with assistant_lock:
509
  if len(assistant_clients) >= MAX_ACTIVE_CLIENTS:
510
  await client.disconnect()
 
603
 
604
  if success:
605
  db_set_active(bot_username, True)
606
+ await msg.edit(f"✅ Registered {bot_username} successfully!\nYou can now use `.val`, `.bash` and `/help` from that account.")
607
  await send_to_log_channel(f"Master: User {uid} registered {bot_username}.")
608
  else:
609
  await msg.edit("Session valid, but failed to start client.")
 
688
 
689
  if __name__ == "__main__":
690
  asyncio.run(main())