chaser-gt 0.1.0

High-performance Geetest v4 captcha solver with automatic deobfuscation
Documentation
# chaser-gt

A high-performance Rust port of [GeekedTest](https://github.com/xKiian/GeekedTest) - a Geetest v4 captcha solver.

## Features

- **Automatic Deobfuscation**: Constants are automatically updated when Geetest releases new versions - no manual intervention required!
- **Multiple Captcha Types**: Supports Slide, Gobang, Icon, and AI/Invisible captchas
- **TLS Fingerprinting**: Uses `rquest` for Chrome-like TLS fingerprinting
- **Proxy Support**: HTTP and SOCKS5 proxy support with authentication
- **Async/Await**: Built on Tokio for efficient concurrent captcha solving
- **Cross-Platform**: Works on Windows, macOS, and Linux

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
chaser-gt = { git = "https://github.com/ccheshirecat/chaser-gt" }
tokio = { version = "1", features = ["full"] }
```

## Quick Start

Basic usage:

```rust
use chaser_gt::{Geeked, RiskType};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create a solver for slide captcha
    let solver = Geeked::builder("your_captcha_id", RiskType::Slide)
        .build()
        .await?;

    // Solve the captcha
    let result = solver.solve().await?;

    println!("captcha_id: {}", result.captcha_id);
    println!("lot_number: {}", result.lot_number);
    println!("pass_token: {}", result.pass_token);
    println!("gen_time: {}", result.gen_time);
    println!("captcha_output: {}", result.captcha_output);

    Ok(())
}
```

## With Proxy

```rust
let solver = Geeked::builder("captcha_id", RiskType::Slide)
    .proxy("http://user:pass@proxy.example.com:8080")  // HTTP proxy
    // or: .proxy("socks5://127.0.0.1:1080")           // SOCKS5 proxy
    .build()
    .await?;
```

## With User Info (Site-Specific Binding)

Some sites require a `user_info` parameter to bind captcha verification to a specific user/session:

```rust
let solver = Geeked::builder("captcha_id", RiskType::Ai)
    .user_info("account_id=12345")  // Site-specific data
    .proxy("http://proxy:8080")
    .build()
    .await?;
```

## With IPv6/Local Address Binding

For scenarios where you need to route captcha solving through a specific network interface or IPv6 address (e.g., BGP exit nodes):

```rust
use std::net::IpAddr;

let ipv6: IpAddr = "2a11:29c0:4f50::1".parse().unwrap();

let solver = Geeked::builder("captcha_id", RiskType::Ai)
    .local_address(ipv6)  // Bind to specific IPv6
    .build()
    .await?;
```

This is useful for:
- **BGP exit nodes**: Route each account through a unique /128 from your subnet
- **Multi-IP setups**: Distribute captcha solving across multiple IPs
- **IP consistency**: Ensure captcha and subsequent requests use the same IP

## Supported Captcha Types

| Type | Enum | Description |
|------|------|-------------|
| Slide | `RiskType::Slide` | Slide puzzle captcha |
| Gobang | `RiskType::Gobang` | Five-in-a-row puzzle |
| Icon | `RiskType::Icon` | Icon selection captcha (requires `icon` feature) |
| AI | `RiskType::Ai` | AI/Invisible captcha |

## Icon Captcha Support

To enable icon captcha support, add the `icon` feature:

```toml
[dependencies]
chaser-gt = { git = "https://github.com/ccheshirecat/chaser-gt", features = ["icon"] }
```

The icon solver uses:
- **ONNX Runtime** for neural network inference
- **Image processing** to detect icon regions
- A bundled **classification model** to identify arrow directions

The ONNX model (`geetest_v4_icon.onnx`) is embedded in the binary for easy distribution.

## Key Improvements

### Automatic Constant Updates

Unlike the Python version which requires manually running `deobfuscate.py` when Geetest updates, this Rust implementation:

1. **Checks for new versions** on startup
2. **Automatically deobfuscates** the Geetest script
3. **Caches constants** to `~/.cache/chaser-gt/constants.json`
4. **Refreshes automatically** when Geetest updates

This means the solver stays functional without any manual intervention!

### Multi-Round Verification Support

Some sites use multi-round verification where Geetest returns `result: "continue"` with updated payload. This library automatically handles the retry loop, making it compatible with sites like shuffle.com that require multiple verification rounds.

## Architecture

```
chaser-gt/
├── src/
│   ├── lib.rs           # Public API exports
│   ├── client.rs        # Main Geeked client
│   ├── deobfuscate.rs   # Auto-deobfuscation system
│   ├── sign.rs          # W parameter generation
│   ├── error.rs         # Error types
│   ├── models.rs        # Data structures
│   ├── crypto/
│   │   ├── aes_enc.rs   # AES-CBC encryption
│   │   ├── rsa_enc.rs   # RSA PKCS1v1.5
│   │   └── pow.rs       # Proof of Work
│   └── solvers/
│       ├── slide.rs     # Slide captcha solver
│       ├── gobang.rs    # Gobang puzzle solver
│       └── icon.rs      # Icon captcha solver
└── models/
    └── geetest_v4_icon.onnx  # ONNX model for icon detection
```

## Building

```bash
cd chaser-gt

# Without icon support
cargo build --release

# With icon support (includes ONNX runtime)
cargo build --release --features icon

# With C FFI bindings
cargo build --release --features ffi
```

## C FFI Bindings

chaser-gt provides C FFI bindings for use from Python, Go, Node.js, C/C++, etc.

### Building FFI Library

```bash
cargo build --release --features ffi

# Library outputs:
# - target/release/libchaser_gt.so (Linux)
# - target/release/libchaser_gt.dylib (macOS)
# - target/release/chaser_gt.dll (Windows)

# C header generated at:
# - include/chaser_gt.h
```

### C Example

```c
#include "chaser_gt.h"
#include <stdio.h>

int main() {
    // Solve a slide captcha (blocking call)
    GeekedResult result = geeked_solve(
        "your_captcha_id",  // captcha_id
        "slide",            // risk_type: slide, gobang, icon, ai
        NULL,               // proxy (optional): "http://user:pass@host:port"
        NULL                // user_info (optional)
    );

    if (result.error_code == 0) {
        printf("lot_number: %s\n", result.lot_number);
        printf("pass_token: %s\n", result.pass_token);
        printf("captcha_output: %s\n", result.captcha_output);
    } else {
        printf("Error: %s\n", result.error_message);
    }

    geeked_free_result(result);
    return 0;
}
```

Compile with:
```bash
gcc -o example example.c -L./target/release -lchaser_gt -lpthread -ldl -lm
```

### Python Example (ctypes)

```python
import ctypes
import json
from ctypes import c_char_p, c_int, Structure, POINTER

# Load library
lib = ctypes.CDLL('./target/release/libchaser_gt.so')  # or .dylib on macOS

# Define result structure
class GeekedResult(Structure):
    _fields_ = [
        ('error_code', c_int),
        ('error_message', c_char_p),
        ('captcha_id', c_char_p),
        ('lot_number', c_char_p),
        ('pass_token', c_char_p),
        ('gen_time', c_char_p),
        ('captcha_output', c_char_p),
    ]

# Or use the simpler JSON API
lib.geeked_solve_json.restype = c_char_p

result_json = lib.geeked_solve_json(
    b"your_captcha_id",
    b"slide",
    None,  # proxy
    None   # user_info
)

result = json.loads(result_json.decode())
lib.geeked_free_string(result_json)

if result['success']:
    print(f"pass_token: {result['pass_token']}")
else:
    print(f"Error: {result['error']}")
```

### FFI Functions

```c
// Solve captcha, returns struct with all fields
GeekedResult geeked_solve(
    const char* captcha_id,   // Required
    const char* risk_type,    // Required: "slide", "gobang", "icon", "ai"
    const char* proxy,        // Optional: "http://host:port" or "socks5://host:port"
    const char* user_info     // Optional: site-specific binding
);

// Solve captcha, returns JSON string
char* geeked_solve_json(
    const char* captcha_id,
    const char* risk_type,
    const char* proxy,
    const char* user_info
);

// Free result struct
void geeked_free_result(GeekedResult result);

// Free string
void geeked_free_string(char* s);

// Get library version
const char* geeked_version();
```

## Running Tests

```bash
# Test without icon feature
cargo test

# Test with icon feature
cargo test --features icon
```

## Running Example

```bash
cargo run --example solve_captcha
```

## Dependencies

Key dependencies:
- `rquest` - HTTP client with TLS fingerprinting
- `tokio` - Async runtime
- `aes`, `rsa`, `sha2` - Cryptography (RustCrypto)
- `image`, `imageproc` - Image processing for slide captcha
- `ort` - ONNX Runtime for icon captcha (optional)

## API Reference

### GeekedResult

The `solve()` method returns a `GeekedResult` containing all the fields needed for verification:

```rust
pub struct GeekedResult {
    pub captcha_id: String,      // The captcha ID used
    pub lot_number: String,      // Unique lot number for this solve
    pub pass_token: String,      // Token to submit to the site
    pub gen_time: String,        // Generation timestamp
    pub captcha_output: String,  // Encrypted captcha output
}
```

### Error Handling

```rust
use chaser_gt::{Geeked, RiskType, GeekedError};

match solver.solve().await {
    Ok(result) => println!("Token: {}", result.pass_token),
    Err(GeekedError::NetworkError(e)) => eprintln!("Network failed: {}", e),
    Err(GeekedError::CaptchaFailed(msg)) => eprintln!("Captcha failed: {}", msg),
    Err(GeekedError::DeobfuscationFailed) => eprintln!("Script deobfuscation failed"),
    Err(e) => eprintln!("Other error: {}", e),
}
```

## Requirements

- Rust 1.70+ (for async traits)
- Internet connection (fetches Geetest scripts for deobfuscation)
- Optional: Proxy for production use

## License

MIT License - same as the original GeekedTest project.

## Acknowledgements

- [GeekedTest]https://github.com/xKiian/GeekedTest - Original Python implementation by xKiian