Add developer docs for CA/CP/PI flows and wire cp-workers to the host SOCKS proxy so local Telegram auth and parsing work reliably. Co-authored-by: Cursor <cursoragent@cursor.com>
116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Интерактивная авторизация Telethon → data/telegram.session.
|
|
|
|
Запуск через образ cp-workers и host-сеть (локальный xray/Happ на 127.0.0.1:10808):
|
|
|
|
docker compose stop cp-workers
|
|
docker run --rm -it --network host \\
|
|
--env-file .env \\
|
|
-e TELEGRAM_SESSION_PATH=/data/telegram.session \\
|
|
-e TELEGRAM_PROXY_HOST=127.0.0.1 \\
|
|
-v \"$PWD/data:/data\" \\
|
|
-v \"$PWD/scripts:/scripts:ro\" \\
|
|
mapmil-cp-workers \\
|
|
python /scripts/telegram_auth.py
|
|
docker compose up -d cp-workers
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
WORKERS = ROOT / "centers" / "parsing" / "workers"
|
|
if WORKERS.exists() and str(WORKERS) not in sys.path:
|
|
sys.path.insert(0, str(WORKERS))
|
|
|
|
|
|
def _load_dotenv(path: Path) -> None:
|
|
if not path.is_file():
|
|
return
|
|
for line in path.read_text(encoding="utf-8").splitlines():
|
|
line = line.strip()
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
key, _, value = line.partition("=")
|
|
key = key.strip()
|
|
value = value.strip().strip("'").strip('"')
|
|
os.environ.setdefault(key, value)
|
|
|
|
|
|
async def main() -> int:
|
|
_load_dotenv(ROOT / ".env")
|
|
|
|
# Prefer repo-local session when running outside Docker /data mount.
|
|
if not os.environ.get("TELEGRAM_SESSION_PATH"):
|
|
local = ROOT / "data" / "telegram.session"
|
|
os.environ["TELEGRAM_SESSION_PATH"] = str(local)
|
|
|
|
from workers.sources.telegram_settings import (
|
|
create_client,
|
|
describe_connection,
|
|
get_api_credentials,
|
|
get_session_path,
|
|
)
|
|
|
|
api_id, api_hash = get_api_credentials()
|
|
session_path = get_session_path()
|
|
Path(session_path).parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
print(f"Сессия: {session_path}")
|
|
print(f"Подключение: {describe_connection()}")
|
|
|
|
client = create_client(session_path, api_id, api_hash)
|
|
await client.connect()
|
|
|
|
if await client.is_user_authorized():
|
|
me = await client.get_me()
|
|
print(
|
|
f"Уже авторизовано: id={me.id} "
|
|
f"username={getattr(me, 'username', None) or '—'} "
|
|
f"phone={getattr(me, 'phone', None) or '—'}"
|
|
)
|
|
await client.disconnect()
|
|
return 0
|
|
|
|
print("Сессия не авторизована — вход в Telegram.")
|
|
phone = input("Номер телефона (+7...): ").strip()
|
|
if not phone:
|
|
print("Номер не указан.", file=sys.stderr)
|
|
await client.disconnect()
|
|
return 1
|
|
|
|
await client.send_code_request(phone)
|
|
code = input("Код из Telegram/SMS: ").strip()
|
|
try:
|
|
await client.sign_in(phone=phone, code=code)
|
|
except Exception as exc:
|
|
# 2FA
|
|
from telethon.errors import SessionPasswordNeededError
|
|
|
|
if not isinstance(exc, SessionPasswordNeededError):
|
|
raise
|
|
password = input("Пароль 2FA: ").strip()
|
|
await client.sign_in(password=password)
|
|
|
|
me = await client.get_me()
|
|
print(
|
|
f"Готово. Авторизован: id={me.id} "
|
|
f"username={getattr(me, 'username', None) or '—'} "
|
|
f"phone={getattr(me, 'phone', None) or '—'}"
|
|
)
|
|
print(f"Файл сессии: {session_path}")
|
|
await client.disconnect()
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
raise SystemExit(asyncio.run(main()))
|
|
except KeyboardInterrupt:
|
|
print("\nОтменено.", file=sys.stderr)
|
|
raise SystemExit(130)
|