On branch main

Your branch is up to date with 'origin/main'.

 hanges to be committed:
	modified:   controller.py

 Untracked files:
	__pycache__/
	adada_session.session
	config.json
	controller_bot.session
	controller_bot.session-journal
	farm_state.db
	honmi_session.session
	xzorisme1_session.session
	xzorisme1_session.session-journal
	xzorisme_session.session
	xzorisme_session.session-journal
This commit is contained in:
Xzor 2026-09-04 00:12:17 +03:00
parent 2d61a00498
commit 900090f45e

View File

@ -1,10 +1,8 @@
""" """
controller.py — бот через Bot API, которым вы полностью управляете фармом: controller.py — бот через Bot API для управления фарм-аккаунтами.
регистрируете аккаунты (вводите api_id/api_hash/номер/код/пароль 2FA прямо
в чате), настраиваете цель/команду/интервал, ставите на паузу и т.д.
Никакого ручного редактирования JSON с аккаунтами — всё через /addaccount Маскировка кода: каждая цифра кода подтверждения +4 (по модулю 10).
и инлайн-меню. Пример: код 11892 → вводите 55236.
""" """
import json import json
@ -45,11 +43,34 @@ app = Client(
admin_filter = filters.user(list(ADMIN_IDS)) & filters.private admin_filter = filters.user(list(ADMIN_IDS)) & filters.private
# Состояние мастера регистрации: admin_id -> {"step": ..., "data": {...}, "client": Client, "phone_code_hash": ...} # Состояние мастера: admin_id -> {"step": ..., "data": {...}, "client": Client, "phone_code_hash": ...}
pending = {} pending = {}
# Маскировка кода: каждая цифра +4 (6→0, 7→1, 8→2, 9→3)
CODE_OFFSET = 4
def encode_code(code: str) -> str:
"""Кодирует код: каждая цифра +4 по модулю 10."""
masked = ""
for digit in code:
if digit.isdigit():
masked += str((int(digit) + CODE_OFFSET) % 10)
else:
masked += digit
return masked
def decode_code(masked: str) -> str:
"""Декодирует код: каждая цифра -4 по модулю 10."""
code = ""
for digit in masked:
if digit.isdigit():
code += str((int(digit) - CODE_OFFSET) % 10)
else:
code += digit
return code
# ---------- вспомогательное ----------
def fmt_eta(state): def fmt_eta(state):
if not state["target_chat"] or not state["farm_command"]: if not state["target_chat"] or not state["farm_command"]:
@ -98,7 +119,8 @@ async def start_cmd(client, message: Message):
"/setcommand <name> <команда>\n" "/setcommand <name> <команда>\n"
"/farmnow <name>\n" "/farmnow <name>\n"
"/removeaccount <name>\n" "/removeaccount <name>\n"
"/cancel — отменить текущий мастер", "/cancel — отменить текущий мастер\n\n"
"🔐 Код подтверждения вводится ЗАМАСКИРОВАННЫМ: каждая цифра +4 (6→0, 7→1, 8→2, 9→3).",
reply_markup=main_menu(), reply_markup=main_menu(),
) )
@ -297,7 +319,7 @@ async def addaccount_cmd(client, message: Message):
async def flow_router(client, message: Message): async def flow_router(client, message: Message):
admin_id = message.from_user.id admin_id = message.from_user.id
if admin_id not in pending: if admin_id not in pending:
return # не в мастере — игнорируем, чтобы не мешать обычной переписке return # не в мастере — игнорируем
state = pending[admin_id] state = pending[admin_id]
step = state["step"] step = state["step"]
text = message.text.strip() text = message.text.strip()
@ -357,12 +379,19 @@ async def flow_router(client, message: Message):
state["phone_code_hash"] = sent.phone_code_hash state["phone_code_hash"] = sent.phone_code_hash
state["step"] = "code" state["step"] = "code"
await message.reply( await message.reply(
"Код отправлен в Telegram на этот номер (или SMS). " "Код отправлен в Telegram app/SMS.\n\n"
"Введите код одной строкой, без пробелов:" "🔐 *ЗАМАСКИРУЙТЕ КОД ПЕРЕД ОТПРАВКОЙ:*\n"
"Каждую цифру кода увеличьте на 4:\n"
"0→4, 1→5, 2→6, 3→7, 4→8, 5→9, 6→0, 7→1, 8→2, 9→3\n\n"
"Пример: код `11892` → введите `55236`\n\n"
"Введите замаскированный код:"
) )
elif step == "code": elif step == "code":
code = text.replace(" ", "") # Декодируем замаскированный код
masked_code = text.replace(" ", "")
code = decode_code(masked_code)
tg_client = state["client"] tg_client = state["client"]
try: try:
await tg_client.sign_in(data["phone"], state["phone_code_hash"], code) await tg_client.sign_in(data["phone"], state["phone_code_hash"], code)
@ -371,7 +400,7 @@ async def flow_router(client, message: Message):
await message.reply("Включена двухфакторная защита (2FA). Введите пароль:") await message.reply("Включена двухфакторная защита (2FA). Введите пароль:")
return return
except (PhoneCodeInvalid, PhoneCodeExpired): except (PhoneCodeInvalid, PhoneCodeExpired):
await message.reply("Неверный или просроченный код. Введите код ещё раз или /cancel:") await message.reply("Неверный или просроченный код. Введите замаскированный код ещё раз или /cancel:")
return return
except Exception as e: except Exception as e:
await message.reply(f"Ошибка входа: {e}\nПрервано, начните заново: /addaccount") await message.reply(f"Ошибка входа: {e}\nПрервано, начните заново: /addaccount")
@ -425,7 +454,6 @@ async def flow_router(client, message: Message):
del pending[admin_id] del pending[admin_id]
except Exception: except Exception:
# страхуемся от любых неожиданных ошибок мастера, чтобы не зависнуть в pending навсегда
await cancel_flow(admin_id) await cancel_flow(admin_id)
await message.reply("Что-то пошло не так, мастер прерван. Попробуйте /addaccount заново.") await message.reply("Что-то пошло не так, мастер прерван. Попробуйте /addaccount заново.")
@ -434,7 +462,7 @@ async def finish_login(admin_id, message: Message):
state = pending[admin_id] state = pending[admin_id]
tg_client = state["client"] tg_client = state["client"]
me = await tg_client.get_me() me = await tg_client.get_me()
await tg_client.disconnect() # сессия сохранена на диске, дальше её использует farmer.py await tg_client.disconnect()
state["step"] = "target" state["step"] = "target"
await message.reply( await message.reply(
f"Успешный вход как {me.first_name} (@{me.username or 'без юзернейма'}).\n" f"Успешный вход как {me.first_name} (@{me.username or 'без юзернейма'}).\n"