<p align="center">
  <h1 align="center">🛡️ GDNox</h1>
  <p align="center">
    <strong>Undetectable Browser Automation Library</strong>
  </p>
  <p align="center">
    Stealth browser automation with closed Shadow DOM access and antibot bypass capabilities
  </p>
</p>

<p align="center">
  <a href="https://pypi.org/project/gdnox/"><img src="https://img.shields.io/pypi/v/gdnox?color=blue&label=PyPI" alt="PyPI Version"></a>
  <a href="https://pypi.org/project/gdnox/"><img src="https://img.shields.io/pypi/pyversions/gdnox" alt="Python Versions"></a>
  <a href="https://github.com/rafaelgdn/GDNox/blob/main/LICENSE"><img src="https://img.shields.io/github/license/rafaelgdn/GDNox?color=green" alt="License"></a>
  <a href="https://github.com/rafaelgdn/GDNox"><img src="https://img.shields.io/github/stars/rafaelgdn/GDNox?style=social" alt="GitHub Stars"></a>
</p>

<p align="center">
  <a href="#-features">Features</a> •
  <a href="#-installation">Installation</a> •
  <a href="#-quick-start">Quick Start</a> •
  <a href="#-stealth-patches">Stealth Patches</a> •
  <a href="#-bypassed-antibots">Bypassed Antibots</a> •
  <a href="#-api-reference">API</a> •
  <a href="./docs/">📚 Documentation</a>
</p>

---

## ✨ Features

| Feature | Description |
|---------|-------------|
| 🔌 **Direct CDP** | Pure Chrome DevTools Protocol - no WebDriver detection |
| 👻 **Shadow DOM Access** | Pierce closed Shadow Roots (impossible with Selenium/Playwright) |
| 🧠 **Human Behavior** | Bezier curve mouse movements, realistic typing delays |
| 🎭 **Fingerprint Spoofing** | Canvas, WebGL, AudioContext randomization |
| 📜 **History Seeding** | Pre-populate browsing history and cookies |
| 🌐 **Proxy Support** | Full proxy support with authentication |
| ⚡ **Async First** | Built on asyncio for high performance |
| 🔄 **Auto OOP Iframe Handling** | Automatically attach to cross-origin iframes |

---

## 📦 Installation

```bash
pip install gdnox
```

Or with Poetry:
```bash
poetry add gdnox
```

### Requirements
- Python 3.10+
- Google Chrome or Chromium installed

---

## 🚀 Quick Start

```python
import asyncio
from GDNox import Browser

async def main():
    async with Browser() as browser:
        tab = await browser.new_tab()
        await tab.goto("https://example.com")
        
        # Find elements - automatically pierces Shadow DOM!
        element = await tab.find("h1")
        print(await element.text())
        
        # Human-like click
        button = await tab.find("button")
        await button.click()  # Uses realistic mouse movement
        
        # Take screenshot
        await tab.screenshot("screenshot.png")

asyncio.run(main())
```

### Clicking Cloudflare Turnstile

```python
import asyncio
from GDNox import Browser

async def solve_turnstile():
    async with Browser() as browser:
        tab = await browser.new_tab()
        await tab.goto("https://example.com/protected-page")
        
        # Wait for iframe to load
        await tab.sleep(3)
        
        # GDNox automatically finds elements inside cross-origin iframes!
        checkbox = await tab.find("input[type='checkbox']")
        if checkbox:
            await checkbox.click()
            print("✅ Clicked Turnstile checkbox!")

asyncio.run(solve_turnstile())
```

---

## 🛡️ Stealth Patches

GDNox applies multiple patches to avoid bot detection:

### Navigator Patches
| Patch | Description |
|-------|-------------|
| `navigator.webdriver` | Removed/undefined (not `false`) |
| `navigator.plugins` | Spoofed with realistic Chrome plugins |
| `navigator.languages` | Configurable language array |
| `navigator.permissions` | Patched `query()` for notifications |

### Browser Object Patches
| Patch | Description |
|-------|-------------|
| `window.chrome` | Complete Chrome runtime object simulation |
| `chrome.runtime` | Mocked `connect()` and `sendMessage()` |
| `chrome.csi` | Mocked timing function |
| `chrome.loadTimes` | Mocked page timing function |

### Fingerprint Randomization
| Patch | Description |
|-------|-------------|
| **Canvas** | Noise injection on `getImageData()` and `toDataURL()` |
| **WebGL** | Spoofed `UNMASKED_VENDOR_WEBGL` and `UNMASKED_RENDERER_WEBGL` |
| **WebGL2** | Same patches for WebGL2 context |
| **Plugins Array** | Realistic PDF plugins when empty |

### Profile Seeding
| Feature | Description |
|---------|-------------|
| **Browser History** | Pre-populated with ~40 popular sites (US + BR) |
| **Cookies** | Realistic tracking cookies for major sites |
| **Local Storage** | Pre-seeded storage for common sites |

### Runtime Evasion
| Technique | Description |
|-----------|-------------|
| **Isolated Worlds** | JavaScript execution in isolated contexts |
| **No Runtime.enable** | Avoids detectable CDP domain activation |
| **No Console.enable** | Prevents console leak detection |

---

## 🎯 Bypassed Antibots

GDNox has been tested against the following antibot solutions:

| Antibot | Status | Notes |
|---------|--------|-------|
| **Cloudflare Turnstile** | ✅ Bypassed | Full shadow DOM + iframe support |
| **Cloudflare Challenge** | ✅ Bypassed | Stealth patches pass checks |
| **DataDome** | ✅ Bypassed | Fingerprint randomization works |
| **PerimeterX (HUMAN)** | ✅ Bypassed | Human behavior simulation |
| **Akamai Bot Manager** | ✅ Bypassed | Sensor data passes validation |
| **Kasada** | ⚠️ Partial | May require additional configuration |
| **Shape Security** | ⚠️ Partial | Depends on site implementation |
| **reCAPTCHA v2** | ⚠️ Detection only | Checkbox can be clicked, solving needs additional service |
| **hCaptcha** | ⚠️ Detection only | Same as reCAPTCHA |

### Shadow Root Access

GDNox can access **closed** Shadow DOMs - something impossible with standard automation tools:

```python
# This works even inside closed shadow roots!
checkbox = await tab.find("input[type='checkbox']")
```

**How it works:**
- Uses `DOM.getDocument` with `pierce: true`
- Automatically traverses all shadow roots
- Resolves elements via `DOM.resolveNode` with `backendNodeId`

---

## 📖 API Reference

### Browser

```python
Browser(
    chrome_path=None,      # Path to Chrome (auto-detected)
    headless=False,        # Headless mode (not recommended for stealth)
    user_data_dir=None,    # Profile directory
    proxy=None,            # Proxy URL (http://user:pass@host:port)
    extra_args=[],         # Additional Chrome arguments
    auto_seed=True,        # Auto-seed history/cookies
)
```

### Tab

```python
await tab.goto(url, wait_until="load", timeout=30.0)
await tab.find(selector, timeout=5.0)
await tab.find_all(selector)
await tab.wait_for_selector(selector, visible=False, timeout=30.0)
await tab.wait_for_function(expression, timeout=30.0)
await tab.race(selectors=[], js_functions=[], timeout=30.0)
await tab.evaluate(expression)
await tab.screenshot(path)
await tab.content()
await tab.sleep(seconds)
```

### Element

```python
await element.click(human_like=True)
await element.type(text, human_like=True)
await element.text()
await element.inner_html()
await element.get_attribute(name)
await element.set_attribute(name, value)
await element.is_visible()
await element.scroll_into_view()
await element.focus()
```

### Network Interception

```python
network = tab.network

@network.on('request')
async def on_request(request):
    print(f"Request: {request.url}")

@network.on('response')
async def on_response(response):
    body = await response.body()
    print(f"Response: {len(body)} bytes")

@network.intercept('*api.example.com*')
async def intercept_api(request):
    if '/blocked' in request.url:
        await request.abort()
    else:
        await request.continue_()
```

---

## 🔧 Advanced Usage

### Custom Fingerprint

```python
from GDNox import Browser
from GDNox.stealth import FingerprintSpoofer

async with Browser() as browser:
    tab = await browser.new_tab()
    
    # Custom WebGL fingerprint
    spoofer = FingerprintSpoofer(
        tab._cdp,
        noise_level=5,
        language="en-US",
        webgl_config=("Intel Inc.", "Intel Iris OpenGL Engine"),
    )
    await spoofer.apply(tab._frame_id)
```

### Human-like Mouse

```python
from GDNox.behavior import HumanMouse

mouse = HumanMouse(tab._cdp)

# Bezier curve movement
await mouse.move_to(500, 300, duration=0.8)

# Natural click
await mouse.click()

# Realistic scroll
await mouse.scroll(delta_y=500)
```

### Profile Management

```python
from GDNox.stealth import ProfileManager

# Create persistent profile with pre-seeded data
profile = ProfileManager("/path/to/profile")
profile.seed_history()
profile.seed_cookies()

# Use with browser
async with Browser(user_data_dir="/path/to/profile", auto_seed=False) as browser:
    ...
```

---

##  License

Apache License 2.0 - See [LICENSE](LICENSE) for details.

---

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

---

<p align="center">
  Made with ❤️ for the automation community
</p>
