Загрузка данных


#!/usr/bin/env python3
"""
AdsPower → Steam OpenID → jabka.to
После успеха на jabka.to:
  Playwright отключается → браузер свободен для ручных действий (капча и т.д.)
  Enter #1 → вставь JWT вручную → POST на /api/accounts
  Enter #2 → закрыть браузер + удалить профиль AdsPower
"""
import sys
import time
from urllib.parse import urlparse
import requests
from playwright.sync_api import sync_playwright

# ====================== НАСТРОЙКИ ======================
ADS_API_BASE = "http://local.adspower.net:50325"
API_KEY = "bb191d39891a5425f133816a601e7cba009ea8f9ff6be779"
ACCOUNTS_API = "http://192.168.0.111:5000/api/accounts"
TARGET_URL = (
    "https://steamcommunity.com/openid/loginform/"
    "?goto=%2Fopenid%2Flogin%3Fopenid.mode%3Dcheckid_setup"
    "%26openid.ns%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0"
    "%26openid.identity%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0%252Fidentifier_select"
    "%26openid.claimed_id%3Dhttp%253A%252F%252Fspecs.openid.net%252Fauth%252F2.0%252Fidentifier_select"
    "%26openid.return_to%3Dhttps%253A%252F%252Fjabauth.com%252Fapi%252Fusers%252Fauth%252Fsteam%252Fvalidate"
    "%253Fregister%253D1%2526r%253Dhttps%25253A%25252F%25252Fjabka.to%25252Fauthenticate"
    "%26openid.realm%3Dhttps%253A%252F%252Fjabauth.com"
)
# =======================================================

HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}",
}

def api_post(path: str, payload: dict, timeout: int = 60) -> dict:
    r = requests.post(f"{ADS_API_BASE}{path}", headers=HEADERS, json=payload, timeout=timeout)
    data = r.json()
    if data.get("code") != 0:
        raise RuntimeError(f"API error {path}: {data.get('msg')} | {data}")
    return data

def check_api() -> bool:
    try:
        r = requests.get(f"{ADS_API_BASE}/status", headers=HEADERS, timeout=5)
        return r.status_code == 200
    except Exception:
        return False

def create_profile() -> str:
    payload = {
        "name": f"steam_jabka_{int(time.time())}",
        "group_id": "0",
        "tabs": [TARGET_URL],
        "user_proxy_config": {"proxy_soft": "no_proxy"},
        "fingerprint_config": {
            "automatic_timezone": "1",
            "language": ["en-US", "en"],
            "flash": "block",
            "fonts": ["all"],
            "webrtc": "disabled",
            "canvas": "1",
            "webgl_image": "1",
            "webgl": "3",
            "audio": "1",
            "do_not_track": "true",
            "hardware_concurrency": "default",
            "device_memory": "default",
            "random_ua": {
                "ua_browser": ["chrome"],
                "ua_system_version": ["Windows 10", "Windows 11"],
            },
        },
    }
    data = api_post("/api/v2/browser-profile/create", payload)
    profile_id = data["data"]["profile_id"]
    print(f"[+] Профиль создан → {profile_id} (№ {data['data']['profile_no']})")
    return profile_id

def start_browser(profile_id: str) -> str:
    payload = {
        "profile_id": profile_id,
        "headless": "0",
        "last_opened_tabs": "1",
        "proxy_detection": "0",
        "cdp_mask": "1",
    }
    data = api_post("/api/v2/browser-profile/start", payload)
    ws = data["data"]["ws"]["puppeteer"]
    print(f"[+] Браузер запущен → {ws}")
    return ws

def stop_browser(profile_id: str):
    try:
        requests.get(
            f"{ADS_API_BASE}/api/v1/browser/stop",
            params={"user_id": profile_id},
            headers=HEADERS,
            timeout=15,
        )
        print("[*] Браузер закрыт")
    except Exception as e:
        print(f"[!] Не удалось закрыть браузер: {e}")

def delete_profile(profile_id: str):
    try:
        data = api_post("/api/v2/browser-profile/delete", {"profile_id": [profile_id]})
        print(f"[*] Профиль удалён: {data.get('msg', 'ok')}")
    except Exception as e:
        print(f"[!] Не удалось удалить профиль: {e}")

def is_jwt(s: str) -> bool:
    parts = s.strip().split(".")
    return len(parts) == 3 and all(parts)

def parse_login_password(s: str):
    if ":" not in s:
        return None, None
    login, password = s.split(":", 1)
    login, password = login.strip(), password.strip()
    if login and password:
        return login, password
    return None, None

def host_is(url: str, *domains: str) -> bool:
    try:
        host = (urlparse(url).hostname or "").lower()
        return any(host == d or host.endswith("." + d) for d in domains)
    except Exception:
        return False

def visible(el) -> bool:
    try:
        return el is not None and el.is_visible()
    except Exception:
        return False

def is_steam_guard_visible(page) -> bool:
    for sel in ["#twofactorcode_entry", "#authcode", "input[name='authcode']"]:
        try:
            el = page.query_selector(sel)
            if visible(el):
                return True
        except Exception:
            continue
    return False

def post_account(jwt_token: str):
    headers = {
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/155.0.0.0 Safari/537.36"
        ),
        "Content-Type": "application/json",
        "Referer": "http://192.168.0.111:5000/",
    }
    payload = {"jwt_token": jwt_token}
    print(f"[*] POST {ACCOUNTS_API}")
    print(f"    body: {payload}")
    try:
        r = requests.post(ACCOUNTS_API, headers=headers, json=payload, timeout=30, verify=False)
        print(f"[+] Ответ {r.status_code}: {r.text[:500]}")
    except Exception as e:
        print(f"[!] Ошибка POST: {e}")

def fill_steam_login(page, login: str, password: str):
    print("[*] Ищем поля логина Steam...")
    page.wait_for_selector(
        "input[type='text'], input[type='password'], #steamAccountName",
        timeout=30000,
    )
    time.sleep(1.2)

    for selector in ["#steamAccountName", "input[name='username']", "input[type='text']", "form input[type='text']"]:
        try:
            el = page.query_selector(selector)
            if visible(el):
                el.click()
                el.fill("")
                el.type(login, delay=35)
                print(f"[+] Логин введён ({selector})")
                break
        except Exception:
            continue
    else:
        raise RuntimeError("Не удалось найти поле логина")

    for selector in ["#steamPassword", "input[name='password']", "input[type='password']", "form input[type='password']"]:
        try:
            el = page.query_selector(selector)
            if visible(el):
                el.click()
                el.fill("")
                el.type(password, delay=35)
                print(f"[+] Пароль введён ({selector})")
                break
        except Exception:
            continue
    else:
        raise RuntimeError("Не удалось найти поле пароля")

    time.sleep(0.4)

    for sel in [
        "button:has-text('Sign in')",
        "button:has-text('Войти')",
        "button[type='submit']",
        "input[type='submit']",
        "form button",
    ]:
        try:
            btn = page.query_selector(sel)
            if visible(btn):
                btn.click()
                print(f"[+] Первый «Войти» → {sel}")
                return
        except Exception:
            continue

    page.keyboard.press("Enter")
    print("[+] Enter (fallback)")

def click_openid_confirm(page) -> bool:
    selectors = [
        "#imageLogin",
        "input#imageLogin",
        "input.btn_green_white_innerfade[type='submit']",
        "input[type='submit'][value='Войти']",
        "input[type='submit'][value='Sign In']",
        "input[type='submit'][value='Sign in']",
        "form#openidForm input[type='submit']",
        "form[name='loginForm'] input[type='submit']",
    ]
    for sel in selectors:
        try:
            el = page.query_selector(sel)
            if visible(el):
                el.click()
                print(f"[+] OpenID «Войти» → {sel}")
                return True
        except Exception:
            continue

    try:
        page.wait_for_selector("#imageLogin", state="visible", timeout=10000)
        el = page.query_selector("#imageLogin")
        if el:
            el.click()
            print("[+] #imageLogin (после wait)")
            return True
    except Exception:
        pass

    print("[!] #imageLogin не найдена")
    return False

def wait_openid_and_confirm(page, timeout_sec: int = 90) -> bool:
    print("[*] Ждём OpenID-подтверждение и жмём «Войти»...")
    deadline = time.time() + timeout_sec
    guard_warned = False

    while time.time() < deadline:
        url = page.url
        if host_is(url, "jabka.to", "jabauth.com"):
            print(f"[+] Уже на целевом домене: {url}")
            return True

        if is_steam_guard_visible(page):
            if not guard_warned:
                print("[!] Steam Guard виден — введи код вручную.")
                guard_warned = True
            time.sleep(2)
            continue

        guard_warned = False

        host = (urlparse(url).hostname or "").lower()
        on_steam = "steamcommunity.com" in host
        has_btn = visible(page.query_selector("#imageLogin"))
        has_card = (
            visible(page.query_selector(".OpenID_UserContainer"))
            or visible(page.query_selector(".OpenID_loggedInName"))
            or visible(page.query_selector(".OpenID_loggedInAccount"))
        )

        if on_steam and (has_btn or has_card or "/openid/" in url):
            if has_btn or has_card:
                print(f"[+] OpenID-подтверждение: {url[:90]}...")
                time.sleep(0.5)
                if click_openid_confirm(page):
                    time.sleep(2)
                    if host_is(page.url, "jabka.to", "jabauth.com"):
                        return True
                    if visible(page.query_selector("#imageLogin")):
                        click_openid_confirm(page)
                    return True
            else:
                try:
                    page.wait_for_selector("#imageLogin", state="visible", timeout=5000)
                    if click_openid_confirm(page):
                        return True
                except Exception:
                    pass

        time.sleep(0.5)

    print("[!] Таймаут OpenID")
    return False

def wait_until_jabka(page, timeout_sec: int = 150) -> bool:
    print("[*] Ждём hostname jabka.to ...")
    deadline = time.time() + timeout_sec
    while time.time() < deadline:
        url = page.url
        if host_is(url, "jabka.to"):
            print(f"[+] Успех! URL: {url}")
            return True
        if host_is(url, "jabauth.com"):
            print("[+] jabauth.com, ждём редирект...")
            time.sleep(1.5)
            continue
        if visible(page.query_selector("#imageLogin")):
            print("[*] #imageLogin ещё видна — кликаем")
            click_openid_confirm(page)
        time.sleep(1.0)
    print(f"[!] Таймаут. URL: {page.url}")
    return False

def main():
    print("=== AdsPower → Steam OpenID → jabka.to ===\n")

    if not check_api():
        print("[-] Local API недоступен.")
        sys.exit(1)
    print("[+] Local API доступен")

    profile_id = None
    try:
        profile_id = create_profile()
        time.sleep(1)
        ws_endpoint = start_browser(profile_id)

        # ---------- Playwright только до jabka.to ----------
        with sync_playwright() as p:
            browser = p.chromium.connect_over_cdp(ws_endpoint)
            context = browser.contexts[0]
            page = context.pages[0] if context.pages else context.new_page()

            if "steamcommunity.com" not in page.url:
                page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=60000)

            print("\n" + "=" * 55)
            print("Введи JWT или login:password")
            print("=" * 55)
            user_input = input(">>> ").strip()
            if not user_input:
                return

            # ---------- JWT напрямую ----------
            if is_jwt(user_input) or (":" not in user_input and len(user_input) > 40):
                token = user_input.strip()
                page.goto(
                    f"https://jabka.to/authenticate?token={token}",
                    wait_until="domcontentloaded",
                    timeout=60000,
                )
                print("\n[✓] Перешли по JWT на jabka.to")
            else:
                # ---------- login:password ----------
                login, password = parse_login_password(user_input)
                if not login:
                    print("[-] Нужен login:password или JWT")
                    return

                print(f"[*] Логин: {login}")
                fill_steam_login(page, login, password)
                wait_openid_and_confirm(page, timeout_sec=90)
                success = wait_until_jabka(page, timeout_sec=150)

                if not success:
                    print("\n[!] Не дождались jabka.to")
                    print(f"    URL: {page.url}")
                    input("\nEnter — закрыть...")
                    return

                print("\n[✓] Авторизация на jabka.to завершена.")

            # Здесь Playwright отключается — браузер остаётся открытым
            print("\n[*] Playwright отключён. Браузер полностью свободен.")
            print("    Решай капчу / делай что нужно руками.")

        # ---------- Дальше только руками + Enter'ы ----------
        print("\n" + "=" * 55)
        print("Enter #1 — вставь JWT (cookie 'token') и отправить в БД")
        print("          (DevTools → Application → Cookies → token)")
        print("=" * 55)
        jwt_token = input(">>> ").strip()

        if jwt_token:
            print(f"[JWT] token = {jwt_token}")
            post_account(jwt_token)
        else:
            print("[!] JWT не введён — POST пропущен")

        print("\n" + "=" * 55)
        print("Enter #2 — закрыть браузер и удалить профиль AdsPower")
        print("=" * 55)
        input(">>> ")

    except Exception as e:
        print(f"[-] Ошибка: {e}")
        raise
    finally:
        if profile_id:
            stop_browser(profile_id)
            time.sleep(1)
            delete_profile(profile_id)

if __name__ == "__main__":
    import urllib3
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    main()