# -*- coding: utf-8 -*-
"""
test_dex.py - Python tester for DexProtectX flow
Tests: Homepage -> Login -> Protection upload
Run: python test_dex.py
"""
import sys, io
# Force UTF-8 output so box chars don't crash on Windows cp1252
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')

import requests
import sys
import os
import time

# ── CONFIG ────────────────────────────────────────────────
USERNAME  = "slex"
PASSWORD  = "pppp0000"
BASE_URL  = "https://dexshellx.com"

# Dummy minimal APK (valid ZIP header so server won't reject instantly)
# We'll create a tiny fake APK just to test the request flow
DUMMY_APK_PATH = "test_dummy.apk"

# Real Chrome-like headers
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
}


def make_dummy_apk():
    """Create a minimal fake APK (ZIP with PK header) for testing."""
    # Real APKs are ZIPs. Minimal valid ZIP signature
    data = (
        b'PK\x03\x04\x14\x00\x00\x00\x08\x00'
        + b'\x00' * 20
        + b'AndroidManifest.xml'
        + b'\x00' * 100
        + b'PK\x05\x06' + b'\x00' * 18
    )
    with open(DUMMY_APK_PATH, "wb") as f:
        f.write(data)
    print(f"[+] Created dummy APK: {DUMMY_APK_PATH} ({len(data)} bytes)")


def step1_homepage(session):
    print("\n" + "="*50)
    print("STEP 1: Visiting homepage to get Cloudflare cookies")
    print("="*50)
    try:
        r = session.get(BASE_URL + "/", headers=HEADERS, timeout=30, allow_redirects=True)
        print(f"[→] GET {BASE_URL}/")
        print(f"[←] HTTP {r.status_code}")
        print(f"[←] Final URL: {r.url}")
        print(f"[←] Cookies set: {dict(session.cookies)}")

        if r.status_code in [200, 301, 302]:
            if "Just a moment" in r.text or "challenge" in r.text.lower():
                print("[!] ⚠ Cloudflare JS Challenge detected! PHP cannot pass this.")
                print("[!]   Response preview:", r.text[:300])
                return False
            print("[✓] Homepage OK — no Cloudflare wall")
            return True
        else:
            print(f"[✗] Unexpected status: {r.status_code}")
            return False
    except Exception as e:
        print(f"[✗] Exception: {e}")
        return False


def step2_login(session):
    print("\n" + "="*50)
    print("STEP 2: Login to DexProtectX")
    print("="*50)

    login_url = BASE_URL + "/dex/login"

    # GET the login page first (see actual form fields)
    try:
        print(f"[->] GET {login_url}")
        r = session.get(login_url, headers=HEADERS, timeout=20)
        print(f"[<-] HTTP {r.status_code}")

        # Save the full login page HTML so we can inspect it
        with open("login_page.html", "w", encoding="utf-8", errors="replace") as f:
            f.write(r.text)
        print("[i] Login page HTML saved to: login_page.html")

        if "Just a moment" in r.text or "challenge" in r.text.lower():
            print("[!] Cloudflare blocked login page GET!")
            return False

        # Find ALL input fields in the form
        import re
        inputs = re.findall(r'<input([^>]+)>', r.text, re.I)
        print(f"\n[i] Form inputs found ({len(inputs)}):")
        for inp in inputs:
            name  = re.search(r'name=["\']([^"\']+)["\']', inp)
            itype = re.search(r'type=["\']([^"\']+)["\']', inp)
            val   = re.search(r'value=["\']([^"\']*)["\']', inp)
            n = name.group(1)  if name  else "(no name)"
            t = itype.group(1) if itype else "text"
            v = val.group(1)   if val   else ""
            print(f"    name={n!r:30} type={t:10} value={v!r}")

        # Also look for any action= in the form tag
        form_actions = re.findall(r'<form([^>]+)>', r.text, re.I)
        print(f"\n[i] Form tags found ({len(form_actions)}):")
        for fa in form_actions:
            print(f"    {fa.strip()}")

        # Extract CSRF token
        csrf = ""
        m = re.search(r'<input[^>]+name=["\']_token["\'][^>]+value=["\'](.*?)["\']', r.text, re.I)
        if not m:
            m = re.search(r'<meta[^>]+name=["\']csrf-token["\'][^>]+content=["\'](.*?)["\']', r.text, re.I)
        if not m:
            # Try any hidden input
            m = re.search(r'<input[^>]+type=["\']hidden["\'][^>]+name=["\']([^"\']+)["\'][^>]+value=["\'](.*?)["\']', r.text, re.I)
            if m:
                print(f"[i] Hidden field: name={m.group(1)!r} value={m.group(2)[:20]!r}")
        if m:
            csrf = m.group(1) if len(m.groups()) == 1 else m.group(2)
            print(f"[+] CSRF/hidden token: {csrf[:30]}...")
        else:
            print("[!] No hidden/CSRF token found")

        # Try login with different possible field name combos
        combos = [
            {"username": USERNAME, "password": PASSWORD},
            {"email": USERNAME,    "password": PASSWORD},
            {"user": USERNAME,     "password": PASSWORD},
            {"login": USERNAME,    "password": PASSWORD},
            {"uname": USERNAME,    "passwd": PASSWORD},
        ]

        post_headers = {**HEADERS, **{
            "Content-Type": "application/x-www-form-urlencoded",
            "Origin": BASE_URL,
            "Referer": login_url,
            "Sec-Fetch-Site": "same-origin",
        }}

        for combo in combos:
            payload = {**combo, "_token": csrf}
            print(f"\n[->] POST {login_url} | fields={list(combo.keys())}")
            r2 = session.post(login_url, data=payload, headers=post_headers, timeout=20, allow_redirects=True)
            print(f"[<-] HTTP {r2.status_code} | Final URL: {r2.url}")

            if r2.status_code == 403:
                print("    [x] 403 Forbidden — wrong fields or bad credentials")
                continue

            if "Just a moment" in r2.text or "challenge" in r2.text.lower():
                print("    [!] Cloudflare blocked!")
                continue

            if "/login" not in r2.url:
                print("    [OK] Login SUCCESS — redirected away from /login!")
                return True

            if "dashboard" in r2.text.lower() or "protection" in r2.text.lower():
                print("    [OK] Login SUCCESS — dashboard keyword in response!")
                return True

            print("    [x] Still on login page")

        print("\n[x] All login combos failed. See login_page.html for actual form.")
        return False

    except Exception as e:
        print(f"[x] Exception: {e}")
        return False



def step3_upload(session):
    print("\n" + "="*50)
    print("STEP 3: Upload APK for protection")
    print("="*50)

    protect_url = BASE_URL + "/dex/protection/options?mode=standard"

    upload_headers = {
        "User-Agent": HEADERS["User-Agent"],
        "Accept": "application/octet-stream,application/vnd.android.package-archive,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Origin": BASE_URL,
        "Referer": protect_url,
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Upgrade-Insecure-Requests": "1",
    }

    with open(DUMMY_APK_PATH, "rb") as f:
        files = {"file": ("test.apk", f, "application/vnd.android.package-archive")}
        data = {
            "string_encryption_filters": "com.test",
            "hide_access_filters":       "com.test",
            "class_encryption_filters":  "com.test",
            "annotation_encryption":     "on",
            "string_encryption":         "on",
            "hide_access":               "on",
            "class_encryption":          "on",
            "jni_obfuscation":           "on",
            "native_lib_encryption":     "on",
            "webview":                   "on",
            "manifest_mangling":         "on",
            "assets":                    "on",
            "resources":                 "on",
            "name_obfuscation":          "on",
            "root_detection":            "on",
            "strings":                   "on",
            "optimize_build":            "on",
            "remove_logs":               "on",
            "crash_handler":             "on",
            "anti_emulator":             "on",
            "anti_xposed":               "on",
            "anti_root_runtime_checks":  "on",
            "mode":                      "standard",
        }

        try:
            print(f"[→] POST {protect_url}")
            print("[→] Uploading... (this may take time)")
            start = time.time()
            r = session.post(protect_url, headers=upload_headers, files=files, data=data, timeout=120, allow_redirects=True)
            elapsed = round(time.time() - start, 1)
            print(f"[←] HTTP {r.status_code} | Time: {elapsed}s")
            print(f"[←] Content-Type: {r.headers.get('Content-Type', 'N/A')}")
            print(f"[←] Content-Length: {len(r.content)} bytes")
            print(f"[←] Final URL: {r.url}")

            ct = r.headers.get("Content-Type", "")
            if r.status_code == 200 and ("octet-stream" in ct or "package-archive" in ct or "zip" in ct):
                print("[✓] SUCCESS — Got APK back!")
                with open("result_protected.apk", "wb") as out:
                    out.write(r.content)
                print("[✓] Saved as result_protected.apk")
            elif "Just a moment" in r.text or "challenge" in r.text.lower():
                print("[!] ⚠ Cloudflare blocked the upload POST!")
                print("[!] Preview:", r.text[:500])
            else:
                print("[✗] No APK returned — see response below:")
                print("-"*40)
                print(r.text[:1000])
                # Save full response
                with open("upload_debug.html", "w", encoding="utf-8") as dbg:
                    dbg.write(r.text)
                print("[i] Full response saved to: upload_debug.html")

        except Exception as e:
            print(f"[✗] Exception during upload: {e}")


def main():
    print("╔══════════════════════════════════════════╗")
    print("║  DexProtectX Python Flow Tester          ║")
    print("╚══════════════════════════════════════════╝")

    make_dummy_apk()

    session = requests.Session()
    session.verify = False  # ignore SSL warnings like PHP does

    import urllib3
    urllib3.disable_warnings()

    # Step 1
    ok = step1_homepage(session)
    if not ok:
        print("\n[ABORT] Cannot proceed — homepage blocked by Cloudflare.")
        print("[TIP]   The site uses a JS challenge which PHP/Python cannot solve.")
        print("[TIP]   Consider using Selenium or a bypass service.")
        sys.exit(1)

    # Step 2
    ok = step2_login(session)
    if not ok:
        print("\n[ABORT] Login failed.")
        sys.exit(1)

    # Step 3
    step3_upload(session)

    print("\n" + "="*50)
    print("TEST COMPLETE")
    print("="*50)


if __name__ == "__main__":
    main()
