From b1edb94a68e3ce3be356fc0daa4159d96b91b66f Mon Sep 17 00:00:00 2001 From: bshahin Date: Sun, 18 Oct 2026 02:51:34 +0300 Subject: [PATCH] Remove hCaptcha and GeeTest v4 example packs (not supported) CaptchaAI does not solve hCaptcha or GeeTest v4, so these two packs claimed support we do not have. Their companion blog articles are already gone (both URLs return 404). - delete articles/how-to-solve-hcaptcha-using-api/ - delete articles/how-to-solve-geetest-v4-using-api/ - drop their two rows from the README index (323 -> 321 packs) GeeTest v3 packs are unaffected. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 - .../.env.example | 13 - .../.gitignore | 25 - .../README.md | 129 ---- .../bash/solve.sh | 195 ----- .../csharp/Solve.cs | 230 ------ .../csharp/Solve.csproj | 6 - .../go/go.mod | 3 - .../go/solve.go | 283 -------- .../java/Solve.java | 265 ------- .../kotlin/solve.kt | 250 ------- .../node/package.json | 14 - .../node/solve.js | 177 ----- .../php/composer.json | 7 - .../php/solve.php | 167 ----- .../python/requirements.txt | 2 - .../python/solve.py | 179 ----- .../ruby/Gemfile | 2 - .../ruby/solve.rb | 191 ----- .../rust/Cargo.toml | 9 - .../rust/src/main.rs | 260 ------- .../.env.example | 13 - .../.gitignore | 20 - .../how-to-solve-hcaptcha-using-api/README.md | 120 ---- .../bash/solve.sh | 171 ----- .../csharp/Solve.cs | 205 ------ .../csharp/Solve.csproj | 6 - .../how-to-solve-hcaptcha-using-api/go/go.mod | 3 - .../go/solve.go | 238 ------ .../java/Solve.java | 221 ------ .../kotlin/solve.kt | 213 ------ .../node/package.json | 14 - .../node/solve.js | 167 ----- .../php/composer.json | 7 - .../php/solve.php | 157 ---- .../python/requirements.txt | 2 - .../python/solve.py | 169 ----- .../ruby/Gemfile | 2 - .../ruby/solve.rb | 184 ----- .../rust/Cargo.lock | 675 ------------------ .../rust/Cargo.toml | 9 - .../rust/src/main.rs | 219 ------ 42 files changed, 5224 deletions(-) delete mode 100644 articles/how-to-solve-geetest-v4-using-api/.env.example delete mode 100644 articles/how-to-solve-geetest-v4-using-api/.gitignore delete mode 100644 articles/how-to-solve-geetest-v4-using-api/README.md delete mode 100644 articles/how-to-solve-geetest-v4-using-api/bash/solve.sh delete mode 100644 articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs delete mode 100644 articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj delete mode 100644 articles/how-to-solve-geetest-v4-using-api/go/go.mod delete mode 100644 articles/how-to-solve-geetest-v4-using-api/go/solve.go delete mode 100644 articles/how-to-solve-geetest-v4-using-api/java/Solve.java delete mode 100644 articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt delete mode 100644 articles/how-to-solve-geetest-v4-using-api/node/package.json delete mode 100644 articles/how-to-solve-geetest-v4-using-api/node/solve.js delete mode 100644 articles/how-to-solve-geetest-v4-using-api/php/composer.json delete mode 100644 articles/how-to-solve-geetest-v4-using-api/php/solve.php delete mode 100644 articles/how-to-solve-geetest-v4-using-api/python/requirements.txt delete mode 100644 articles/how-to-solve-geetest-v4-using-api/python/solve.py delete mode 100644 articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile delete mode 100644 articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb delete mode 100644 articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml delete mode 100644 articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs delete mode 100644 articles/how-to-solve-hcaptcha-using-api/.env.example delete mode 100644 articles/how-to-solve-hcaptcha-using-api/.gitignore delete mode 100644 articles/how-to-solve-hcaptcha-using-api/README.md delete mode 100644 articles/how-to-solve-hcaptcha-using-api/bash/solve.sh delete mode 100644 articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs delete mode 100644 articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj delete mode 100644 articles/how-to-solve-hcaptcha-using-api/go/go.mod delete mode 100644 articles/how-to-solve-hcaptcha-using-api/go/solve.go delete mode 100644 articles/how-to-solve-hcaptcha-using-api/java/Solve.java delete mode 100644 articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt delete mode 100644 articles/how-to-solve-hcaptcha-using-api/node/package.json delete mode 100644 articles/how-to-solve-hcaptcha-using-api/node/solve.js delete mode 100644 articles/how-to-solve-hcaptcha-using-api/php/composer.json delete mode 100644 articles/how-to-solve-hcaptcha-using-api/php/solve.php delete mode 100644 articles/how-to-solve-hcaptcha-using-api/python/requirements.txt delete mode 100644 articles/how-to-solve-hcaptcha-using-api/python/solve.py delete mode 100644 articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile delete mode 100644 articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb delete mode 100644 articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock delete mode 100644 articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml delete mode 100644 articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs diff --git a/README.md b/README.md index dcded63..f614d94 100644 --- a/README.md +++ b/README.md @@ -221,9 +221,7 @@ Internal factory scripts, tools, and templates are intentionally not part of thi | [how-to-solve-cloudflare-challenge-using-api](articles/how-to-solve-cloudflare-challenge-using-api/) | Cloudflare Challenge | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-cloudflare-challenge-using-api) | | [how-to-solve-cloudflare-turnstile-using-api](articles/how-to-solve-cloudflare-turnstile-using-api/) | Cloudflare Turnstile | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-cloudflare-turnstile-using-api) | | [how-to-solve-geetest-v3-using-api](articles/how-to-solve-geetest-v3-using-api/) | GeeTest v3 | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-geetest-v3-using-api) | -| [how-to-solve-geetest-v4-using-api](articles/how-to-solve-geetest-v4-using-api/) | GeeTest v4 | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-geetest-v4-using-api) | | [how-to-solve-grid-image-captcha-automatically](articles/how-to-solve-grid-image-captcha-automatically/) | Grid Image CAPTCHA | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-grid-image-captcha-automatically) | -| [how-to-solve-hcaptcha-using-api](articles/how-to-solve-hcaptcha-using-api/) | hCaptcha | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-hcaptcha-using-api) | | [how-to-solve-recaptcha-invisible-using-api](articles/how-to-solve-recaptcha-invisible-using-api/) | reCAPTCHA Invisible | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-invisible-using-api) | | [how-to-solve-recaptcha-v2-callback-using-api](articles/how-to-solve-recaptcha-v2-callback-using-api/) | reCAPTCHA v2 | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-v2-callback-using-api) | | [how-to-solve-recaptcha-v2-enterprise-using-api](articles/how-to-solve-recaptcha-v2-enterprise-using-api/) | reCAPTCHA v2 Enterprise | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-v2-enterprise-using-api) | diff --git a/articles/how-to-solve-geetest-v4-using-api/.env.example b/articles/how-to-solve-geetest-v4-using-api/.env.example deleted file mode 100644 index 27825c9..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# CaptchaAI API credentials -# Get your API key from https://captchaai.com/dashboard -CAPTCHAAI_API_KEY=YOUR_API_KEY - -# Target page configuration -# GeeTest v4 captcha_id value from the target page -CAPTCHA_GT=YOUR_GT_VALUE -# Full URL of the page -CAPTCHA_PAGEURL=https://example.com - -# Polling configuration (optional) -POLL_INTERVAL=5 -MAX_TIMEOUT=120 diff --git a/articles/how-to-solve-geetest-v4-using-api/.gitignore b/articles/how-to-solve-geetest-v4-using-api/.gitignore deleted file mode 100644 index 8a0d20d..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -.env -__pycache__/ -*.pyc -node_modules/ -vendor/ -composer.lock -package-lock.json -.DS_Store -Thumbs.db -# Go -go.sum -# Java -*.class -# C# -bin/ -obj/ -# Ruby -Gemfile.lock -# Rust -target/ -Cargo.lock -# Kotlin -*.jar -# Bash -*.log diff --git a/articles/how-to-solve-geetest-v4-using-api/README.md b/articles/how-to-solve-geetest-v4-using-api/README.md deleted file mode 100644 index f4c57f0..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/README.md +++ /dev/null @@ -1,129 +0,0 @@ -# GeeTest v4 — CaptchaAI Example Pack - -Full working example for solving GeeTest v4 using the CaptchaAI API. - -**Languages:** Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash - -## Related article - -This example accompanies the blog article: -**[How to Solve GeeTest v4 Using API](https://blog.captchaai.com/how-to-solve-geetest-v4-using-api)** - -## Prerequisites - -- A CaptchaAI account with API key ([get one here](https://captchaai.com)) -- A target page with GeeTest v4 for testing -- One or more of: Python 3.8+, Node.js 16+, PHP 8.0+, Go 1.21+, Java 11+, .NET 8+, Ruby 3.0+, Rust 1.70+, Kotlin 1.9+, or Bash with curl and jq - -## GeeTest v4 parameters - -| Parameter | Required | Description | -|-----------|----------|-------------| -| `gt` | Yes | The `captcha_id` — GeeTest v4 identifier for the site (find in page source or GeeTest v4 init call) | -| `version` | Yes | Must be `4` for GeeTest v4 | -| `pageurl` | Yes | Full URL of the page with the GeeTest v4 widget | - -> **Note:** Unlike GeeTest v3, GeeTest v4 does **not** require a `challenge` parameter. - -## Response - -The API returns five values that must be submitted together to the site's GeeTest v4 verification endpoint: - -- `captcha_id` — the GeeTest captcha identifier -- `lot_number` — the lot number for this solve -- `pass_token` — the pass token -- `gen_time` — the generation timestamp -- `captcha_output` — the captcha output value - -## Setup - -1. Clone the repository: - ```bash - git clone https://github.com/CaptchaAI/CaptchaAI-Examples.git - cd CaptchaAI-Examples/articles/how-to-solve-geetest-v4-using-api - ``` - -2. Copy the environment file and add your credentials: - ```bash - cp .env.example .env - ``` - -3. Edit `.env` with your API key and target page details. - -4. Follow the language-specific setup below. - -### Python - -```bash -cd python -pip install -r requirements.txt -python solve.py -``` - -### Node.js - -```bash -cd node -npm install -node solve.js -``` - -### PHP - -```bash -cd php -composer install -php solve.php -``` - -### Go - -```bash -cd go -go run solve.go -``` - -### Java - -```bash -cd java -javac Solve.java -java Solve -``` - -### C# - -```bash -cd csharp -dotnet run -``` - -### Ruby - -```bash -cd ruby -ruby solve.rb -``` - -### Rust - -```bash -cd rust -cargo run -``` - -### Kotlin - -```bash -cd kotlin -kotlinc solve.kt -include-runtime -d solve.jar -java -jar solve.jar -``` - -### Bash - -```bash -cd bash -chmod +x solve.sh -bash solve.sh -``` diff --git a/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh b/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh deleted file mode 100644 index fb3152a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env bash -# Solve GeeTest v4 using the CaptchaAI API. -# -# Usage: -# chmod +x solve.sh -# bash solve.sh - -set -euo pipefail - -SUBMIT_URL="https://ocr.captchaai.com/in.php" -RESULT_URL="https://ocr.captchaai.com/res.php" - -# Load .env -ENV_FILE="$(dirname "$0")/../.env" -if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - source "$ENV_FILE" - set +a -fi - -API_KEY="${CAPTCHAAI_API_KEY:-}" -GT="${CAPTCHA_GT:-}" -PAGEURL="${CAPTCHA_PAGEURL:-}" -POLL_INTERVAL="${POLL_INTERVAL:-5}" -MAX_TIMEOUT="${MAX_TIMEOUT:-120}" - -# Validate -if [[ -z "$API_KEY" || "$API_KEY" == "YOUR_API_KEY" ]]; then - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set." - echo " Copy .env.example to .env and add your real API key." - exit 1 -fi -if [[ -z "$GT" || "$GT" == "YOUR_CAPTCHA_ID" ]]; then - echo "[!] ERROR: CAPTCHA_GT is not set." - echo " Find the captcha_id in the page source or GeeTest v4 initialization call." - exit 1 -fi -if [[ -z "$PAGEURL" || "$PAGEURL" == "https://example.com" ]]; then - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - echo " Make sure it points to the actual target page." -fi - -# JSON helpers -json_str() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\"\\K[^\"]*" || echo "" -} -json_int() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\\K[0-9]+" || echo "0" -} - -# Error handler -handle_error() { - local error="$1" - case "$error" in - ERROR_WRONG_USER_KEY|ERROR_KEY_DOES_NOT_EXIST|IP_BANNED) - echo "[!] Authentication error: $error" - echo " Check your API key at https://captchaai.com/dashboard" - ;; - ERROR_ZERO_BALANCE) - echo "[!] Balance error: $error" - echo " Top up your account at https://captchaai.com" - ;; - ERROR_PAGEURL|ERROR_WRONG_GOOGLEKEY|ERROR_BAD_PARAMETERS|ERROR_BAD_TOKEN_OR_PAGEURL) - echo "[!] Input error: $error" - echo " Verify your gt (captcha_id) and page URL are correct." - ;; - ERROR_BAD_PROXY|ERROR_PROXY_CONNECTION_FAILED) - echo "[!] Proxy error: $error" - echo " Check your proxy configuration or try a different proxy." - ;; - *) - echo "[!] Submission failed: $error" - ;; - esac -} - -# Submit task -echo "[*] Submitting GeeTest v4 task..." -ENCODED_KEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$API_KEY'))" 2>/dev/null || echo "$API_KEY") -ENCODED_GT=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$GT'))" 2>/dev/null || echo "$GT") -ENCODED_PAGEURL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAGEURL'))" 2>/dev/null || echo "$PAGEURL") - -SUBMIT_QUERY="key=${ENCODED_KEY}&method=geetest>=${ENCODED_GT}&pageurl=${ENCODED_PAGEURL}&version=4&json=1" - -SUBMIT_RESP=$(curl -sS --max-time 30 "${SUBMIT_URL}?${SUBMIT_QUERY}") - -if [[ -z "$SUBMIT_RESP" ]]; then - echo "[!] Network error during submission." - exit 1 -fi - -SUBMIT_STATUS=$(json_int "$SUBMIT_RESP" "status") -SUBMIT_REQUEST=$(json_str "$SUBMIT_RESP" "request") - -if [[ "$SUBMIT_STATUS" -ne 1 ]]; then - handle_error "$SUBMIT_REQUEST" - exit 1 -fi - -TASK_ID="$SUBMIT_REQUEST" -echo "[+] Task submitted. ID: $TASK_ID" - -# Poll for result -echo "[*] Waiting 15s before first poll..." -sleep 15 - -ELAPSED=15 -ATTEMPT=0 -BACKOFF="$POLL_INTERVAL" - -while [[ "$ELAPSED" -lt "$MAX_TIMEOUT" ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "[*] Polling for result (attempt $ATTEMPT)..." - - POLL_RESP=$(curl -sS --max-time 30 \ - "${RESULT_URL}?key=${ENCODED_KEY}&action=get&id=${TASK_ID}&json=1" 2>/dev/null || echo "") - - if [[ -z "$POLL_RESP" ]]; then - echo "[!] Network error during polling." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - fi - - STATUS=$(json_int "$POLL_RESP" "status") - - if [[ "$STATUS" -eq 1 ]]; then - # Extract the 5 GeeTest v4 values from the response - CAPTCHA_ID_VAL=$(echo "$POLL_RESP" | grep -oP '"captcha_id"\s*:\s*"\\K[^"]*' || echo "") - LOT_NUMBER=$(echo "$POLL_RESP" | grep -oP '"lot_number"\s*:\s*"\\K[^"]*' || echo "") - PASS_TOKEN=$(echo "$POLL_RESP" | grep -oP '"pass_token"\s*:\s*"\\K[^"]*' || echo "") - GEN_TIME=$(echo "$POLL_RESP" | grep -oP '"gen_time"\s*:\s*"\\K[^"]*' || echo "") - CAPTCHA_OUTPUT=$(echo "$POLL_RESP" | grep -oP '"captcha_output"\s*:\s*"\\K[^"]*' || echo "") - - # If values are empty, the request might be a JSON string — try extracting from unescaped content - if [[ -z "$CAPTCHA_ID_VAL" ]]; then - REQUEST_VALUE=$(json_str "$POLL_RESP" "request") - # Unescape the JSON string and extract values - UNESCAPED=$(echo "$REQUEST_VALUE" | sed 's/\\"/"/g; s/\\\\/\\/g') - CAPTCHA_ID_VAL=$(echo "$UNESCAPED" | grep -oP '"captcha_id"\s*:\s*"\\K[^"]*' || echo "") - LOT_NUMBER=$(echo "$UNESCAPED" | grep -oP '"lot_number"\s*:\s*"\\K[^"]*' || echo "") - PASS_TOKEN=$(echo "$UNESCAPED" | grep -oP '"pass_token"\s*:\s*"\\K[^"]*' || echo "") - GEN_TIME=$(echo "$UNESCAPED" | grep -oP '"gen_time"\s*:\s*"\\K[^"]*' || echo "") - CAPTCHA_OUTPUT=$(echo "$UNESCAPED" | grep -oP '"captcha_output"\s*:\s*"\\K[^"]*' || echo "") - fi - - echo "[+] Solved!" - echo "[+] captcha_id: $CAPTCHA_ID_VAL" - echo "[+] lot_number: $LOT_NUMBER" - echo "[+] pass_token: $PASS_TOKEN" - echo "[+] gen_time: $GEN_TIME" - echo "[+] captcha_output: $CAPTCHA_OUTPUT" - echo - echo "Next step: submit these five values to the site's" - echo "GeeTest v4 verification endpoint." - exit 0 - fi - - REQUEST=$(json_str "$POLL_RESP" "request") - - if [[ "$REQUEST" == "CAPCHA_NOT_READY" ]]; then - echo "[*] Not ready yet, waiting ${POLL_INTERVAL}s..." - sleep "$POLL_INTERVAL" - ELAPSED=$((ELAPSED + POLL_INTERVAL)) - BACKOFF="$POLL_INTERVAL" - continue - fi - - case "$REQUEST" in - ERROR_SERVER_ERROR|ERROR_INTERNAL_SERVER_ERROR) - echo "[!] Transient error: $REQUEST, retrying in ${BACKOFF}s..." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - ;; - ERROR_CAPTCHA_UNSOLVABLE) - echo "[!] Solve error: $REQUEST" - echo " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - ;; - esac - - echo "[!] Unexpected error: $REQUEST" - exit 1 -done - -echo "[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds." -exit 1 diff --git a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs b/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs deleted file mode 100644 index b950017..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// dotnet run - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; - -const string SubmitUrl = "https://ocr.captchaai.com/in.php"; -const string ResultUrl = "https://ocr.captchaai.com/res.php"; - -var authErrors = new HashSet { "ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED" }; -var balanceErrors = new HashSet { "ERROR_ZERO_BALANCE" }; -var inputErrors = new HashSet { "ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL" }; -var transientErrors = new HashSet { "ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR" }; -var solveErrors = new HashSet { "ERROR_CAPTCHA_UNSOLVABLE" }; -var proxyErrors = new HashSet { "ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED" }; - -var env = LoadEnv(Path.Combine("..", ".env")); -string apiKey = GetEnv(env, "CAPTCHAAI_API_KEY", ""); -string gt = GetEnv(env, "CAPTCHA_GT", ""); -string pageurl = GetEnv(env, "CAPTCHA_PAGEURL", ""); -int pollInterval = int.Parse(GetEnv(env, "POLL_INTERVAL", "5")); -int maxTimeout = int.Parse(GetEnv(env, "MAX_TIMEOUT", "120")); - -// Validate -if (string.IsNullOrEmpty(apiKey) || apiKey == "YOUR_API_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - Console.WriteLine(" Copy .env.example to .env and add your real API key."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(gt) || gt == "YOUR_CAPTCHA_ID") -{ - Console.WriteLine("[!] ERROR: CAPTCHA_GT is not set."); - Console.WriteLine(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(pageurl) || pageurl == "https://example.com") -{ - Console.WriteLine("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - Console.WriteLine(" Make sure it points to the actual target page."); -} - -using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; - -// Submit task -Console.WriteLine("[*] Submitting GeeTest v4 task..."); -var submitQuery = $"key={Uri.EscapeDataString(apiKey)}&method=geetest>={Uri.EscapeDataString(gt)}&pageurl={Uri.EscapeDataString(pageurl)}&version=4&json=1"; - -string submitBody; -try -{ - submitBody = await client.GetStringAsync($"{SubmitUrl}?{submitQuery}"); -} -catch (Exception ex) -{ - Console.WriteLine($"[!] Network error during submission: {ex.Message}"); - Environment.Exit(1); - return; -} - -using var submitDoc = JsonDocument.Parse(submitBody); -int submitStatus = submitDoc.RootElement.GetProperty("status").GetInt32(); -string submitRequest = submitDoc.RootElement.GetProperty("request").GetString() ?? ""; - -if (submitStatus != 1) -{ - HandleError(submitRequest, authErrors, balanceErrors, inputErrors, proxyErrors); - Environment.Exit(1); -} - -string taskId = submitRequest; -Console.WriteLine($"[+] Task submitted. ID: {taskId}"); - -// Poll for result -Console.WriteLine("[*] Waiting 15s before first poll..."); -await Task.Delay(15000); - -int elapsed = 15; -int attempt = 0; -int backoff = pollInterval; - -while (elapsed < maxTimeout) -{ - attempt++; - Console.WriteLine($"[*] Polling for result (attempt {attempt})..."); - - var pollQuery = $"key={Uri.EscapeDataString(apiKey)}&action=get&id={Uri.EscapeDataString(taskId)}&json=1"; - - string resultBody; - try - { - resultBody = await client.GetStringAsync($"{ResultUrl}?{pollQuery}"); - } - catch (Exception ex) - { - Console.WriteLine($"[!] Network error during polling: {ex.Message}"); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - using var resultDoc = JsonDocument.Parse(resultBody); - int status = resultDoc.RootElement.GetProperty("status").GetInt32(); - var requestElement = resultDoc.RootElement.GetProperty("request"); - - if (status == 1) - { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - JsonDocument solutionDoc; - if (requestElement.ValueKind == JsonValueKind.String) - { - solutionDoc = JsonDocument.Parse(requestElement.GetString()!); - } - else - { - solutionDoc = JsonDocument.Parse(requestElement.GetRawText()); - } - - string captchaId = solutionDoc.RootElement.GetProperty("captcha_id").GetString() ?? ""; - string lotNumber = solutionDoc.RootElement.GetProperty("lot_number").GetString() ?? ""; - string passToken = solutionDoc.RootElement.GetProperty("pass_token").GetString() ?? ""; - string genTime = solutionDoc.RootElement.GetProperty("gen_time").GetString() ?? ""; - string captchaOutput = solutionDoc.RootElement.GetProperty("captcha_output").GetString() ?? ""; - solutionDoc.Dispose(); - - Console.WriteLine("[+] Solved!"); - Console.WriteLine($"[+] captcha_id: {captchaId}"); - Console.WriteLine($"[+] lot_number: {lotNumber}"); - Console.WriteLine($"[+] pass_token: {passToken}"); - Console.WriteLine($"[+] gen_time: {genTime}"); - Console.WriteLine($"[+] captcha_output: {captchaOutput}"); - Console.WriteLine(); - Console.WriteLine("Next step: submit these five values to the site's"); - Console.WriteLine("GeeTest v4 verification endpoint."); - return; - } - - string request = requestElement.ValueKind == JsonValueKind.String - ? requestElement.GetString() ?? "" - : ""; - - if (request == "CAPCHA_NOT_READY") - { - Console.WriteLine($"[*] Not ready yet, waiting {pollInterval}s..."); - await Task.Delay(pollInterval * 1000); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (transientErrors.Contains(request)) - { - Console.WriteLine($"[!] Transient error: {request}, retrying in {backoff}s..."); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - if (solveErrors.Contains(request)) - { - Console.WriteLine($"[!] Solve error: {request}"); - Console.WriteLine(" The CAPTCHA could not be solved. Verify parameters and retry."); - Environment.Exit(1); - } - - Console.WriteLine($"[!] Unexpected error: {request}"); - Environment.Exit(1); -} - -Console.WriteLine($"[!] Timeout: no solution received within {maxTimeout} seconds."); -Environment.Exit(1); - -static Dictionary LoadEnv(string path) -{ - var dict = new Dictionary(); - if (!File.Exists(path)) return dict; - foreach (var line in File.ReadAllLines(path)) - { - var trimmed = line.Trim(); - if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith('#')) continue; - var eq = trimmed.IndexOf('='); - if (eq > 0) - dict[trimmed[..eq].Trim()] = trimmed[(eq + 1)..].Trim(); - } - return dict; -} - -static string GetEnv(Dictionary env, string key, string fallback) -{ - if (env.TryGetValue(key, out var v) && !string.IsNullOrEmpty(v)) return v; - v = Environment.GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(v)) return v; - return fallback; -} - -static void HandleError(string error, HashSet auth, HashSet balance, HashSet input, HashSet proxy) -{ - if (auth.Contains(error)) - { - Console.WriteLine($"[!] Authentication error: {error}"); - Console.WriteLine(" Check your API key at https://captchaai.com/dashboard"); - } - else if (balance.Contains(error)) - { - Console.WriteLine($"[!] Balance error: {error}"); - Console.WriteLine(" Top up your account at https://captchaai.com"); - } - else if (input.Contains(error)) - { - Console.WriteLine($"[!] Input error: {error}"); - Console.WriteLine(" Verify your gt (captcha_id) and page URL are correct."); - } - else if (proxy.Contains(error)) - { - Console.WriteLine($"[!] Proxy error: {error}"); - Console.WriteLine(" Check your proxy configuration or try a different proxy."); - } - else - { - Console.WriteLine($"[!] Submission failed: {error}"); - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj b/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj deleted file mode 100644 index dd4b568..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - Exe - net8.0 - - diff --git a/articles/how-to-solve-geetest-v4-using-api/go/go.mod b/articles/how-to-solve-geetest-v4-using-api/go/go.mod deleted file mode 100644 index 36f97d4..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module captchaai-geetest-v4-example - -go 1.21 diff --git a/articles/how-to-solve-geetest-v4-using-api/go/solve.go b/articles/how-to-solve-geetest-v4-using-api/go/solve.go deleted file mode 100644 index 93fdb5c..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/go/solve.go +++ /dev/null @@ -1,283 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// go run solve.go - -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "time" -) - -const submitURL = "https://ocr.captchaai.com/in.php" -const resultURL = "https://ocr.captchaai.com/res.php" - -var authErrors = map[string]bool{"ERROR_WRONG_USER_KEY": true, "ERROR_KEY_DOES_NOT_EXIST": true, "IP_BANNED": true} -var balanceErrors = map[string]bool{"ERROR_ZERO_BALANCE": true} -var inputErrors = map[string]bool{"ERROR_PAGEURL": true, "ERROR_WRONG_GOOGLEKEY": true, "ERROR_BAD_PARAMETERS": true, "ERROR_BAD_TOKEN_OR_PAGEURL": true} -var transientErrors = map[string]bool{"ERROR_SERVER_ERROR": true, "ERROR_INTERNAL_SERVER_ERROR": true} -var solveErrors = map[string]bool{"ERROR_CAPTCHA_UNSOLVABLE": true} -var proxyErrors = map[string]bool{"ERROR_BAD_PROXY": true, "ERROR_PROXY_CONNECTION_FAILED": true} - -type apiResponse struct { - Status int `json:"status"` - Request any `json:"request"` -} - -type geetestV4Solution struct { - CaptchaID string `json:"captcha_id"` - LotNumber string `json:"lot_number"` - PassToken string `json:"pass_token"` - GenTime string `json:"gen_time"` - CaptchaOutput string `json:"captcha_output"` -} - -func requestValue(value any) string { - switch v := value.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func handleError(error string) { - if authErrors[error] { - fmt.Printf("[!] Authentication error: %s\n", error) - fmt.Println(" Check your API key at https://captchaai.com/dashboard") - } else if balanceErrors[error] { - fmt.Printf("[!] Balance error: %s\n", error) - fmt.Println(" Top up your account at https://captchaai.com") - } else if inputErrors[error] { - fmt.Printf("[!] Input error: %s\n", error) - fmt.Println(" Verify your gt (captcha_id) and page URL are correct.") - } else if proxyErrors[error] { - fmt.Printf("[!] Proxy error: %s\n", error) - fmt.Println(" Check your proxy configuration or try a different proxy.") - } else { - fmt.Printf("[!] Submission failed: %s\n", error) - } -} - -func getRequestString(raw any) string { - switch v := raw.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - case map[string]any: - data, err := json.Marshal(v) - if err == nil { - return string(data) - } - case []any: - data, err := json.Marshal(v) - if err == nil { - return string(data) - } - case json.RawMessage: - var s string - if err := json.Unmarshal(v, &s); err == nil { - return s - } - return string(v) - } - return fmt.Sprintf("%v", raw) -} - -func loadEnv() map[string]string { - path := filepath.Join("..", ".env") - env := make(map[string]string) - f, err := os.Open(path) - if err != nil { - return env - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - env[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) - } - } - - return env -} - -func getEnv(env map[string]string, key, fallback string) string { - if value, ok := env[key]; ok && value != "" { - return value - } - if value := os.Getenv(key); value != "" { - return value - } - return fallback -} - -func main() { - env := loadEnv() - apiKey := getEnv(env, "CAPTCHAAI_API_KEY", "") - gt := getEnv(env, "CAPTCHA_GT", "") - pageurl := getEnv(env, "CAPTCHA_PAGEURL", "") - pollInterval, _ := strconv.Atoi(getEnv(env, "POLL_INTERVAL", "5")) - maxTimeout, _ := strconv.Atoi(getEnv(env, "MAX_TIMEOUT", "120")) - - if apiKey == "" || apiKey == "YOUR_API_KEY" { - fmt.Println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - fmt.Println(" Copy .env.example to .env and add your real API key.") - os.Exit(1) - } - if gt == "" || gt == "YOUR_CAPTCHA_ID" { - fmt.Println("[!] ERROR: CAPTCHA_GT is not set.") - fmt.Println(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - os.Exit(1) - } - if pageurl == "" || pageurl == "https://example.com" { - fmt.Println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - fmt.Println(" Make sure it points to the actual target page.") - } - - client := &http.Client{Timeout: 30 * time.Second} - - // Submit task - fmt.Println("[*] Submitting GeeTest v4 task...") - params := url.Values{ - "key": {apiKey}, - "method": {"geetest"}, - "gt": {gt}, - "pageurl": {pageurl}, - "version": {"4"}, - "json": {"1"}, - } - - resp, err := client.Get(submitURL + "?" + params.Encode()) - if err != nil { - fmt.Printf("[!] Network error during submission: %v\n", err) - os.Exit(1) - } - defer resp.Body.Close() - - body, _ := io.ReadAll(resp.Body) - var submitResp apiResponse - json.Unmarshal(body, &submitResp) - - if submitResp.Status != 1 { - handleError(getRequestString(submitResp.Request)) - os.Exit(1) - } - - taskID := getRequestString(submitResp.Request) - fmt.Printf("[+] Task submitted. ID: %s\n", taskID) - - // Poll for result - fmt.Println("[*] Waiting 15s before first poll...") - time.Sleep(15 * time.Second) - - elapsed := 15 - attempt := 0 - backoff := pollInterval - - for elapsed < maxTimeout { - attempt++ - fmt.Printf("[*] Polling for result (attempt %d)...\n", attempt) - - pollParams := url.Values{ - "key": {apiKey}, - "action": {"get"}, - "id": {taskID}, - "json": {"1"}, - } - - resp, err := client.Get(resultURL + "?" + pollParams.Encode()) - if err != nil { - fmt.Printf("[!] Network error during polling: %v\n", err) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - body, _ := io.ReadAll(resp.Body) - resp.Body.Close() - var result apiResponse - json.Unmarshal(body, &result) - - if result.Status == 1 { - var solution geetestV4Solution - solutionPayload := getRequestString(result.Request) - if err := json.Unmarshal([]byte(solutionPayload), &solution); err != nil { - fmt.Printf("[!] Failed to parse GeeTest v4 solution: %v\n", err) - os.Exit(1) - } - fmt.Println("[+] Solved!") - fmt.Printf("[+] captcha_id: %s\n", solution.CaptchaID) - fmt.Printf("[+] lot_number: %s\n", solution.LotNumber) - fmt.Printf("[+] pass_token: %s\n", solution.PassToken) - fmt.Printf("[+] gen_time: %s\n", solution.GenTime) - fmt.Printf("[+] captcha_output: %s\n", solution.CaptchaOutput) - fmt.Println() - fmt.Println("Next step: submit these five values to the site's") - fmt.Println("GeeTest v4 verification endpoint.") - return - } - - reqStr := getRequestString(result.Request) - - if reqStr == "CAPCHA_NOT_READY" { - fmt.Printf("[*] Not ready yet, waiting %ds...\n", pollInterval) - time.Sleep(time.Duration(pollInterval) * time.Second) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if transientErrors[reqStr] { - fmt.Printf("[!] Transient error: %s, retrying in %ds...\n", reqStr, backoff) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - if solveErrors[reqStr] { - fmt.Printf("[!] Solve error: %s\n", reqStr) - fmt.Println(" The CAPTCHA could not be solved. Verify parameters and retry.") - os.Exit(1) - } - - fmt.Printf("[!] Unexpected error: %s\n", reqStr) - os.Exit(1) - } - - fmt.Printf("[!] Timeout: no solution received within %d seconds.\n", maxTimeout) - os.Exit(1) -} diff --git a/articles/how-to-solve-geetest-v4-using-api/java/Solve.java b/articles/how-to-solve-geetest-v4-using-api/java/Solve.java deleted file mode 100644 index 94a22aa..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/java/Solve.java +++ /dev/null @@ -1,265 +0,0 @@ -import java.io.*; -import java.net.*; -import java.nio.file.*; -import java.util.*; - -/** - * Solve GeeTest v4 using the CaptchaAI API. - * - * Usage: - * javac Solve.java - * java Solve - */ -public class Solve { - static final String SUBMIT_URL = "https://ocr.captchaai.com/in.php"; - static final String RESULT_URL = "https://ocr.captchaai.com/res.php"; - - static final Set AUTH_ERRORS = Set.of("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"); - static final Set BALANCE_ERRORS = Set.of("ERROR_ZERO_BALANCE"); - static final Set INPUT_ERRORS = Set.of("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"); - static final Set TRANSIENT_ERRORS = Set.of("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"); - static final Set SOLVE_ERRORS = Set.of("ERROR_CAPTCHA_UNSOLVABLE"); - static final Set PROXY_ERRORS = Set.of("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"); - - static Map env = new HashMap<>(); - - public static void main(String[] args) throws Exception { - loadEnv(); - String apiKey = getEnv("CAPTCHAAI_API_KEY", ""); - String gt = getEnv("CAPTCHA_GT", ""); - String pageurl = getEnv("CAPTCHA_PAGEURL", ""); - int pollInterval = Integer.parseInt(getEnv("POLL_INTERVAL", "5")); - int maxTimeout = Integer.parseInt(getEnv("MAX_TIMEOUT", "120")); - - // Validate - if (apiKey.isEmpty() || apiKey.equals("YOUR_API_KEY")) { - System.out.println("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - System.out.println(" Copy .env.example to .env and add your real API key."); - System.exit(1); - } - if (gt.isEmpty() || gt.equals("YOUR_CAPTCHA_ID")) { - System.out.println("[!] ERROR: CAPTCHA_GT is not set."); - System.out.println(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - System.exit(1); - } - if (pageurl.isEmpty() || pageurl.equals("https://example.com")) { - System.out.println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - System.out.println(" Make sure it points to the actual target page."); - } - - // Submit task - System.out.println("[*] Submitting GeeTest v4 task..."); - String submitParams = String.format( - "key=%s&method=geetest>=%s&pageurl=%s&version=4&json=1", - enc(apiKey), enc(gt), enc(pageurl) - ); - - String submitResp = httpGet(SUBMIT_URL + "?" + submitParams); - int submitStatus = jsonInt(submitResp, "status"); - String submitRequest = jsonStr(submitResp, "request"); - - if (submitStatus != 1) { - handleError(submitRequest); - System.exit(1); - } - - String taskId = submitRequest; - System.out.println("[+] Task submitted. ID: " + taskId); - - // Poll for result - System.out.println("[*] Waiting 15s before first poll..."); - Thread.sleep(15000); - - int elapsed = 15; - int attempt = 0; - int backoff = pollInterval; - - while (elapsed < maxTimeout) { - attempt++; - System.out.println("[*] Polling for result (attempt " + attempt + ")..."); - - String pollParams = String.format( - "key=%s&action=get&id=%s&json=1", - enc(apiKey), enc(taskId) - ); - - String resultResp; - try { - resultResp = httpGet(RESULT_URL + "?" + pollParams); - } catch (Exception e) { - System.out.println("[!] Network error during polling: " + e.getMessage()); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - int status = jsonInt(resultResp, "status"); - - if (status == 1) { - // The request field contains a JSON object with the 5 GeeTest v4 values - String requestValue = extractRequestValue(resultResp); - String captchaId = jsonStr(requestValue, "captcha_id"); - String lotNumber = jsonStr(requestValue, "lot_number"); - String passToken = jsonStr(requestValue, "pass_token"); - String genTime = jsonStr(requestValue, "gen_time"); - String captchaOutput = jsonStr(requestValue, "captcha_output"); - System.out.println("[+] Solved!"); - System.out.println("[+] captcha_id: " + captchaId); - System.out.println("[+] lot_number: " + lotNumber); - System.out.println("[+] pass_token: " + passToken); - System.out.println("[+] gen_time: " + genTime); - System.out.println("[+] captcha_output: " + captchaOutput); - System.out.println(); - System.out.println("Next step: submit these five values to the site's"); - System.out.println("GeeTest v4 verification endpoint."); - return; - } - - String request = jsonStr(resultResp, "request"); - - if ("CAPCHA_NOT_READY".equals(request)) { - System.out.println("[*] Not ready yet, waiting " + pollInterval + "s..."); - Thread.sleep(pollInterval * 1000L); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (TRANSIENT_ERRORS.contains(request)) { - System.out.println("[!] Transient error: " + request + ", retrying in " + backoff + "s..."); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.contains(request)) { - System.out.println("[!] Solve error: " + request); - System.out.println(" The CAPTCHA could not be solved. Verify parameters and retry."); - System.exit(1); - } - - System.out.println("[!] Unexpected error: " + request); - System.exit(1); - } - - System.out.println("[!] Timeout: no solution received within " + maxTimeout + " seconds."); - System.exit(1); - } - - static void loadEnv() { - try { - Path envPath = Paths.get("..", ".env"); - if (!Files.exists(envPath)) return; - for (String line : Files.readAllLines(envPath)) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) continue; - int eq = line.indexOf('='); - if (eq > 0) { - env.put(line.substring(0, eq).trim(), line.substring(eq + 1).trim()); - } - } - } catch (IOException ignored) {} - } - - static String getEnv(String key, String fallback) { - String v = env.get(key); - if (v != null && !v.isEmpty()) return v; - v = System.getenv(key); - if (v != null && !v.isEmpty()) return v; - return fallback; - } - - static String httpGet(String urlStr) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(30000); - conn.setReadTimeout(30000); - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) sb.append(line); - reader.close(); - return sb.toString(); - } - - static String enc(String s) throws Exception { - return URLEncoder.encode(s, "UTF-8"); - } - - static int jsonInt(String json, String key) { - String pattern = "\"" + key + "\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return 0; - int start = idx + pattern.length(); - StringBuilder sb = new StringBuilder(); - for (int i = start; i < json.length(); i++) { - char c = json.charAt(i); - if (c == ',' || c == '}') break; - if (c != ' ') sb.append(c); - } - try { return Integer.parseInt(sb.toString()); } catch (Exception e) { return 0; } - } - - static String jsonStr(String json, String key) { - String pattern = "\"" + key + "\":\""; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - int end = json.indexOf("\"", start); - if (end < 0) return ""; - return json.substring(start, end); - } - - static String extractRequestValue(String json) { - // Find "request": and extract the value — could be a JSON string or JSON object - String pattern = "\"request\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - // Skip whitespace - while (start < json.length() && json.charAt(start) == ' ') start++; - if (start >= json.length()) return ""; - - if (json.charAt(start) == '"') { - // It's a JSON string — extract and unescape - int end = start + 1; - while (end < json.length()) { - if (json.charAt(end) == '\\') { end += 2; continue; } - if (json.charAt(end) == '"') break; - end++; - } - String inner = json.substring(start + 1, end); - return inner.replace("\\\"", "\"").replace("\\\\", "\\"); - } else if (json.charAt(start) == '{') { - // It's a JSON object — find matching brace - int depth = 0; - int end = start; - for (; end < json.length(); end++) { - if (json.charAt(end) == '{') depth++; - else if (json.charAt(end) == '}') { depth--; if (depth == 0) { end++; break; } } - } - return json.substring(start, end); - } - return ""; - } - - static void handleError(String error) { - if (AUTH_ERRORS.contains(error)) { - System.out.println("[!] Authentication error: " + error); - System.out.println(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.contains(error)) { - System.out.println("[!] Balance error: " + error); - System.out.println(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.contains(error)) { - System.out.println("[!] Input error: " + error); - System.out.println(" Verify your gt (captcha_id) and page URL are correct."); - } else if (PROXY_ERRORS.contains(error)) { - System.out.println("[!] Proxy error: " + error); - System.out.println(" Check your proxy configuration or try a different proxy."); - } else { - System.out.println("[!] Submission failed: " + error); - } - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt b/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt deleted file mode 100644 index f2ff0f9..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt +++ /dev/null @@ -1,250 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// kotlinc solve.kt -include-runtime -d solve.jar -// java -jar solve.jar - -import java.io.BufferedReader -import java.io.InputStreamReader -import java.net.HttpURLConnection -import java.net.URL -import java.net.URLEncoder -import java.io.File - -val SUBMIT_URL = "https://ocr.captchaai.com/in.php" -val RESULT_URL = "https://ocr.captchaai.com/res.php" - -val AUTH_ERRORS = setOf("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED") -val BALANCE_ERRORS = setOf("ERROR_ZERO_BALANCE") -val INPUT_ERRORS = setOf("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL") -val TRANSIENT_ERRORS = setOf("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR") -val SOLVE_ERRORS = setOf("ERROR_CAPTCHA_UNSOLVABLE") -val PROXY_ERRORS = setOf("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED") - -fun loadEnv(path: String): Map { - val env = mutableMapOf() - val file = File(path) - if (!file.exists()) return env - file.readLines().forEach { line -> - val trimmed = line.trim() - if (trimmed.isNotEmpty() && !trimmed.startsWith("#")) { - val eq = trimmed.indexOf('=') - if (eq > 0) { - env[trimmed.substring(0, eq).trim()] = trimmed.substring(eq + 1).trim() - } - } - } - return env -} - -fun getEnv(env: Map, key: String, fallback: String = ""): String { - val v = env[key] - if (!v.isNullOrEmpty()) return v - val sv = System.getenv(key) - if (!sv.isNullOrEmpty()) return sv - return fallback -} - -fun httpGet(urlStr: String): String { - val conn = URL(urlStr).openConnection() as HttpURLConnection - conn.connectTimeout = 30000 - conn.readTimeout = 30000 - val reader = BufferedReader(InputStreamReader(conn.inputStream)) - val result = reader.readText() - reader.close() - return result -} - -fun jsonStr(json: String, key: String): String { - val pattern = "\"$key\":\"" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val start = idx + pattern.length - val end = json.indexOf("\"", start) - if (end < 0) return "" - return json.substring(start, end) -} - -fun jsonInt(json: String, key: String): Int { - val pattern = "\"$key\":" - val idx = json.indexOf(pattern) - if (idx < 0) return 0 - val start = idx + pattern.length - val numStr = json.substring(start).takeWhile { it.isDigit() || it == '-' } - return numStr.toIntOrNull() ?: 0 -} - -fun extractRequestJson(json: String): String { - val pattern = "\"request\":" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val rest = json.substring(idx + pattern.length).trimStart() - if (rest.startsWith("\"")) { - // JSON string — find closing quote with escape handling - val inner = rest.substring(1) - var end = 0 - while (end < inner.length) { - if (inner[end] == '\\') { end += 2; continue } - if (inner[end] == '"') break - end++ - } - return inner.substring(0, end).replace("\\\"", "\"").replace("\\\\", "\\") - } else if (rest.startsWith("{")) { - // JSON object — find matching brace - var depth = 0 - for (i in rest.indices) { - if (rest[i] == '{') depth++ - else if (rest[i] == '}') { depth--; if (depth == 0) return rest.substring(0, i + 1) } - } - } - return "" -} - -fun handleError(error: String) { - when { - error in AUTH_ERRORS -> { - println("[!] Authentication error: $error") - println(" Check your API key at https://captchaai.com/dashboard") - } - error in BALANCE_ERRORS -> { - println("[!] Balance error: $error") - println(" Top up your account at https://captchaai.com") - } - error in INPUT_ERRORS -> { - println("[!] Input error: $error") - println(" Verify your gt (captcha_id) and page URL are correct.") - } - error in PROXY_ERRORS -> { - println("[!] Proxy error: $error") - println(" Check your proxy configuration or try a different proxy.") - } - else -> println("[!] Submission failed: $error") - } -} - -fun enc(s: String) = URLEncoder.encode(s, "UTF-8") - -fun main() { - val env = loadEnv("../.env") - val apiKey = getEnv(env, "CAPTCHAAI_API_KEY") - val gt = getEnv(env, "CAPTCHA_GT") - val pageurl = getEnv(env, "CAPTCHA_PAGEURL") - val pollInterval = getEnv(env, "POLL_INTERVAL", "5").toInt() - val maxTimeout = getEnv(env, "MAX_TIMEOUT", "120").toInt() - - // Validate - if (apiKey.isEmpty() || apiKey == "YOUR_API_KEY") { - println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - println(" Copy .env.example to .env and add your real API key.") - System.exit(1) - } - if (gt.isEmpty() || gt == "YOUR_CAPTCHA_ID") { - println("[!] ERROR: CAPTCHA_GT is not set.") - println(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - System.exit(1) - } - if (pageurl.isEmpty() || pageurl == "https://example.com") { - println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - println(" Make sure it points to the actual target page.") - } - - // Submit task - println("[*] Submitting GeeTest v4 task...") - val submitParams = "key=${enc(apiKey)}&method=geetest>=${enc(gt)}&pageurl=${enc(pageurl)}&version=4&json=1" - - val submitResp = try { - httpGet("$SUBMIT_URL?$submitParams") - } catch (e: Exception) { - println("[!] Network error during submission: ${e.message}") - System.exit(1) - return - } - - val submitStatus = jsonInt(submitResp, "status") - val submitRequest = jsonStr(submitResp, "request") - - if (submitStatus != 1) { - handleError(submitRequest) - System.exit(1) - } - - val taskId = submitRequest - println("[+] Task submitted. ID: $taskId") - - // Poll for result - println("[*] Waiting 15s before first poll...") - Thread.sleep(15000) - - var elapsed = 15 - var attempt = 0 - var backoff = pollInterval - - while (elapsed < maxTimeout) { - attempt++ - println("[*] Polling for result (attempt $attempt)...") - - val pollParams = "key=${enc(apiKey)}&action=get&id=${enc(taskId)}&json=1" - - val resultResp = try { - httpGet("$RESULT_URL?$pollParams") - } catch (e: Exception) { - println("[!] Network error during polling: ${e.message}") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - val status = jsonInt(resultResp, "status") - - if (status == 1) { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - val solutionJson = extractRequestJson(resultResp) - val captchaId = jsonStr(solutionJson, "captcha_id") - val lotNumber = jsonStr(solutionJson, "lot_number") - val passToken = jsonStr(solutionJson, "pass_token") - val genTime = jsonStr(solutionJson, "gen_time") - val captchaOutput = jsonStr(solutionJson, "captcha_output") - println("[+] Solved!") - println("[+] captcha_id: $captchaId") - println("[+] lot_number: $lotNumber") - println("[+] pass_token: $passToken") - println("[+] gen_time: $genTime") - println("[+] captcha_output: $captchaOutput") - println() - println("Next step: submit these five values to the site's") - println("GeeTest v4 verification endpoint.") - return - } - - val request = jsonStr(resultResp, "request") - - if (request == "CAPCHA_NOT_READY") { - println("[*] Not ready yet, waiting ${pollInterval}s...") - Thread.sleep(pollInterval * 1000L) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if (request in TRANSIENT_ERRORS) { - println("[!] Transient error: $request, retrying in ${backoff}s...") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - if (request in SOLVE_ERRORS) { - println("[!] Solve error: $request") - println(" The CAPTCHA could not be solved. Verify parameters and retry.") - System.exit(1) - } - - println("[!] Unexpected error: $request") - System.exit(1) - } - - println("[!] Timeout: no solution received within ${maxTimeout} seconds.") - System.exit(1) -} diff --git a/articles/how-to-solve-geetest-v4-using-api/node/package.json b/articles/how-to-solve-geetest-v4-using-api/node/package.json deleted file mode 100644 index d63fd8a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/node/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "captchaai-geetest-v4-example", - "version": "1.0.0", - "description": "Solve GeeTest v4 using CaptchaAI API", - "main": "solve.js", - "scripts": { - "start": "node solve.js" - }, - "dependencies": { - "axios": "^1.6.0", - "dotenv": "^16.3.0" - }, - "license": "MIT" -} diff --git a/articles/how-to-solve-geetest-v4-using-api/node/solve.js b/articles/how-to-solve-geetest-v4-using-api/node/solve.js deleted file mode 100644 index 6ac8f6a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/node/solve.js +++ /dev/null @@ -1,177 +0,0 @@ -/** - * Solve GeeTest v4 using the CaptchaAI API. - * - * Usage: - * npm install - * cp ../.env.example ../.env // then edit with your credentials - * node solve.js - */ - -require("dotenv").config({ path: require("path").join(__dirname, "..", ".env") }); -const axios = require("axios"); - -const SUBMIT_URL = "https://ocr.captchaai.com/in.php"; -const RESULT_URL = "https://ocr.captchaai.com/res.php"; - -const API_KEY = process.env.CAPTCHAAI_API_KEY || ""; -const CAPTCHA_GT = process.env.CAPTCHA_GT || ""; -const CAPTCHA_PAGEURL = process.env.CAPTCHA_PAGEURL || ""; -const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || "5", 10); -const MAX_TIMEOUT = parseInt(process.env.MAX_TIMEOUT || "120", 10); - -const AUTH_ERRORS = new Set(["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]); -const BALANCE_ERRORS = new Set(["ERROR_ZERO_BALANCE"]); -const INPUT_ERRORS = new Set(["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]); -const TRANSIENT_ERRORS = new Set(["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]); -const SOLVE_ERRORS = new Set(["ERROR_CAPTCHA_UNSOLVABLE"]); -const PROXY_ERRORS = new Set(["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]); - -function sleep(seconds) { - return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); -} - -function validateConfig() { - if (!API_KEY || API_KEY === "YOUR_API_KEY") { - console.log("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - console.log(" Copy .env.example to .env and add your real API key."); - process.exit(1); - } - if (!CAPTCHA_GT || CAPTCHA_GT === "YOUR_CAPTCHA_ID") { - console.log("[!] ERROR: CAPTCHA_GT is not set."); - console.log(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - process.exit(1); - } - if (!CAPTCHA_PAGEURL || CAPTCHA_PAGEURL === "https://example.com") { - console.log("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - console.log(" Make sure it points to the actual target page."); - } -} - -async function submitTask() { - console.log("[*] Submitting GeeTest v4 task..."); - - const params = { - key: API_KEY, - method: "geetest", - gt: CAPTCHA_GT, - pageurl: CAPTCHA_PAGEURL, - version: "4", - json: "1", - }; - - let resp; - try { - resp = await axios.get(SUBMIT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during submission: ${err.message}`); - process.exit(1); - } - - const data = resp.data; - if (data.status !== 1) { - const error = data.request || "UNKNOWN_ERROR"; - if (AUTH_ERRORS.has(error)) { - console.log(`[!] Authentication error: ${error}`); - console.log(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.has(error)) { - console.log(`[!] Balance error: ${error}`); - console.log(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.has(error)) { - console.log(`[!] Input error: ${error}`); - console.log(" Verify your gt (captcha_id) and page URL are correct."); - } else if (PROXY_ERRORS.has(error)) { - console.log(`[!] Proxy error: ${error}`); - console.log(" Check your proxy configuration or try a different proxy."); - } else { - console.log(`[!] Submission failed: ${error}`); - } - process.exit(1); - } - - const taskId = data.request; - console.log(`[+] Task submitted. ID: ${taskId}`); - return taskId; -} - -async function pollResult(taskId) { - console.log("[*] Waiting 15s before first poll..."); - await sleep(15); - - const params = { key: API_KEY, action: "get", id: taskId, json: "1" }; - let elapsed = 15; - let attempt = 0; - let backoff = POLL_INTERVAL; - - while (elapsed < MAX_TIMEOUT) { - attempt++; - console.log(`[*] Polling for result (attempt ${attempt})...`); - - let resp; - try { - resp = await axios.get(RESULT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during polling: ${err.message}`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - const data = resp.data; - - if (data.status === 1) { - // The request field contains a JSON string with the 5 GeeTest v4 values - let solution = data.request; - if (typeof solution === "string") { - solution = JSON.parse(solution); - } - return solution; - } - - const error = data.request || ""; - if (error === "CAPCHA_NOT_READY") { - console.log(`[*] Not ready yet, waiting ${POLL_INTERVAL}s...`); - await sleep(POLL_INTERVAL); - elapsed += POLL_INTERVAL; - backoff = POLL_INTERVAL; - continue; - } - - if (TRANSIENT_ERRORS.has(error)) { - console.log(`[!] Transient error: ${error}, retrying in ${backoff}s...`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.has(error)) { - console.log(`[!] Solve error: ${error}`); - console.log(" The CAPTCHA could not be solved. Verify parameters and retry."); - process.exit(1); - } - - console.log(`[!] Unexpected error: ${error}`); - process.exit(1); - } - - console.log(`[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds.`); - process.exit(1); -} - -async function main() { - validateConfig(); - const taskId = await submitTask(); - const solution = await pollResult(taskId); - console.log("[+] Solved!"); - console.log(`[+] captcha_id: ${solution.captcha_id}`); - console.log(`[+] lot_number: ${solution.lot_number}`); - console.log(`[+] pass_token: ${solution.pass_token}`); - console.log(`[+] gen_time: ${solution.gen_time}`); - console.log(`[+] captcha_output: ${solution.captcha_output}`); - console.log(); - console.log("Next step: submit these five values to the site's"); - console.log("GeeTest v4 verification endpoint."); -} - -main(); diff --git a/articles/how-to-solve-geetest-v4-using-api/php/composer.json b/articles/how-to-solve-geetest-v4-using-api/php/composer.json deleted file mode 100644 index 1dfca82..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/php/composer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "captchaai/geetest-v4-example", - "description": "Solve GeeTest v4 using CaptchaAI API", - "require": { - "vlucas/phpdotenv": "^5.5" - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/php/solve.php b/articles/how-to-solve-geetest-v4-using-api/php/solve.php deleted file mode 100644 index f283cd2..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/php/solve.php +++ /dev/null @@ -1,167 +0,0 @@ -load(); - -define('SUBMIT_URL', 'https://ocr.captchaai.com/in.php'); -define('RESULT_URL', 'https://ocr.captchaai.com/res.php'); - -$apiKey = $_ENV['CAPTCHAAI_API_KEY'] ?? ''; -$gt = $_ENV['CAPTCHA_GT'] ?? ''; -$pageurl = $_ENV['CAPTCHA_PAGEURL'] ?? ''; -$pollInterval = (int)($_ENV['POLL_INTERVAL'] ?? 5); -$maxTimeout = (int)($_ENV['MAX_TIMEOUT'] ?? 120); - -$authErrors = ['ERROR_WRONG_USER_KEY', 'ERROR_KEY_DOES_NOT_EXIST', 'IP_BANNED']; -$balanceErrors = ['ERROR_ZERO_BALANCE']; -$inputErrors = ['ERROR_PAGEURL', 'ERROR_WRONG_GOOGLEKEY', 'ERROR_BAD_PARAMETERS', 'ERROR_BAD_TOKEN_OR_PAGEURL']; -$transientErrors = ['ERROR_SERVER_ERROR', 'ERROR_INTERNAL_SERVER_ERROR']; -$solveErrors = ['ERROR_CAPTCHA_UNSOLVABLE']; -$proxyErrors = ['ERROR_BAD_PROXY', 'ERROR_PROXY_CONNECTION_FAILED']; - -// --- Validate configuration --- -if (empty($apiKey) || $apiKey === 'YOUR_API_KEY') { - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set.\n"; - echo " Copy .env.example to .env and add your real API key.\n"; - exit(1); -} -if (empty($gt) || $gt === 'YOUR_CAPTCHA_ID') { - echo "[!] ERROR: CAPTCHA_GT is not set.\n"; - echo " Find the captcha_id in the page source or GeeTest v4 initialization call.\n"; - exit(1); -} -if (empty($pageurl) || $pageurl === 'https://example.com') { - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.\n"; - echo " Make sure it points to the actual target page.\n"; -} - -// --- Submit task --- -echo "[*] Submitting GeeTest v4 task...\n"; -$submitParams = [ - 'key' => $apiKey, - 'method' => 'geetest', - 'gt' => $gt, - 'pageurl' => $pageurl, - 'version' => '4', - 'json' => '1', -]; -$submitQuery = http_build_query($submitParams); - -$ctx = stream_context_create(['http' => ['timeout' => 30]]); -$submitResponse = @file_get_contents(SUBMIT_URL . '?' . $submitQuery, false, $ctx); -if ($submitResponse === false) { - echo "[!] Network error during submission.\n"; - exit(1); -} - -$submitData = json_decode($submitResponse, true); -if (($submitData['status'] ?? 0) !== 1) { - $error = $submitData['request'] ?? 'UNKNOWN_ERROR'; - if (in_array($error, $authErrors)) { - echo "[!] Authentication error: $error\n"; - echo " Check your API key at https://captchaai.com/dashboard\n"; - } elseif (in_array($error, $balanceErrors)) { - echo "[!] Balance error: $error\n"; - echo " Top up your account at https://captchaai.com\n"; - } elseif (in_array($error, $inputErrors)) { - echo "[!] Input error: $error\n"; - echo " Verify your gt (captcha_id) and page URL are correct.\n"; - } elseif (in_array($error, $proxyErrors)) { - echo "[!] Proxy error: $error\n"; - echo " Check your proxy configuration or try a different proxy.\n"; - } else { - echo "[!] Submission failed: $error\n"; - } - exit(1); -} - -$taskId = $submitData['request']; -echo "[+] Task submitted. ID: $taskId\n"; - -// --- Poll for result --- -echo "[*] Waiting 15s before first poll...\n"; -sleep(15); - -$elapsed = 15; -$attempt = 0; -$backoff = $pollInterval; - -while ($elapsed < $maxTimeout) { - $attempt++; - echo "[*] Polling for result (attempt $attempt)...\n"; - - $resultParams = http_build_query([ - 'key' => $apiKey, - 'action' => 'get', - 'id' => $taskId, - 'json' => '1', - ]); - - $resultResponse = @file_get_contents(RESULT_URL . '?' . $resultParams, false, $ctx); - if ($resultResponse === false) { - echo "[!] Network error during polling.\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - $resultData = json_decode($resultResponse, true); - - if (($resultData['status'] ?? 0) === 1) { - // The request field contains a JSON string with the 5 GeeTest v4 values - $solution = $resultData['request']; - if (is_string($solution)) { - $solution = json_decode($solution, true); - } - echo "[+] Solved!\n"; - echo "[+] captcha_id: " . $solution['captcha_id'] . "\n"; - echo "[+] lot_number: " . $solution['lot_number'] . "\n"; - echo "[+] pass_token: " . $solution['pass_token'] . "\n"; - echo "[+] gen_time: " . $solution['gen_time'] . "\n"; - echo "[+] captcha_output: " . $solution['captcha_output'] . "\n"; - echo "\n"; - echo "Next step: submit these five values to the site's\n"; - echo "GeeTest v4 verification endpoint.\n"; - exit(0); - } - - $error = $resultData['request'] ?? ''; - if ($error === 'CAPCHA_NOT_READY') { - echo "[*] Not ready yet, waiting {$pollInterval}s...\n"; - sleep($pollInterval); - $elapsed += $pollInterval; - $backoff = $pollInterval; - continue; - } - - if (in_array($error, $transientErrors)) { - echo "[!] Transient error: $error, retrying in {$backoff}s...\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - if (in_array($error, $solveErrors)) { - echo "[!] Solve error: $error\n"; - echo " The CAPTCHA could not be solved. Verify parameters and retry.\n"; - exit(1); - } - - echo "[!] Unexpected error: $error\n"; - exit(1); -} - -echo "[!] Timeout: no solution received within {$maxTimeout} seconds.\n"; -exit(1); diff --git a/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt b/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt deleted file mode 100644 index f49b6b8..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests>=2.28.0 -python-dotenv>=1.0.0 diff --git a/articles/how-to-solve-geetest-v4-using-api/python/solve.py b/articles/how-to-solve-geetest-v4-using-api/python/solve.py deleted file mode 100644 index 9974040..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/python/solve.py +++ /dev/null @@ -1,179 +0,0 @@ -"""Solve GeeTest v4 using the CaptchaAI API. - -Usage: - pip install -r requirements.txt - cp ../.env.example ../.env # then edit with your credentials - python solve.py -""" - -import os -import sys -import time -import json - -import requests -from dotenv import load_dotenv - -# Load environment variables from the parent .env file -load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env")) - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -API_KEY = os.getenv("CAPTCHAAI_API_KEY", "") -CAPTCHA_GT = os.getenv("CAPTCHA_GT", "") -CAPTCHA_PAGEURL = os.getenv("CAPTCHA_PAGEURL", "") -POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "5")) -MAX_TIMEOUT = int(os.getenv("MAX_TIMEOUT", "120")) - -# --- Error categories --- -AUTH_ERRORS = {"ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"} -BALANCE_ERRORS = {"ERROR_ZERO_BALANCE"} -INPUT_ERRORS = {"ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"} -TRANSIENT_ERRORS = {"ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"} -SOLVE_ERRORS = {"ERROR_CAPTCHA_UNSOLVABLE"} -PROXY_ERRORS = {"ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"} - - -def validate_config() -> None: - """Check that required environment variables are set.""" - if not API_KEY or API_KEY == "YOUR_API_KEY": - print("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - print(" Copy .env.example to .env and add your real API key.") - sys.exit(1) - if not CAPTCHA_GT or CAPTCHA_GT == "YOUR_CAPTCHA_ID": - print("[!] ERROR: CAPTCHA_GT is not set.") - print(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - sys.exit(1) - if not CAPTCHA_PAGEURL or CAPTCHA_PAGEURL == "https://example.com": - print("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - print(" Make sure it points to the actual target page.") - - -def submit_task() -> str: - """Submit the CAPTCHA task and return the task ID.""" - print("[*] Submitting GeeTest v4 task...") - payload = { - "key": API_KEY, - "method": "geetest", - "gt": CAPTCHA_GT, - "pageurl": CAPTCHA_PAGEURL, - "version": "4", - "json": "1", - } - - try: - resp = requests.get(SUBMIT_URL, params=payload, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during submission: {exc}") - sys.exit(1) - - data = resp.json() - - if data.get("status") != 1: - error = data.get("request", "UNKNOWN_ERROR") - if error in AUTH_ERRORS: - print(f"[!] Authentication error: {error}") - print(" Check your API key at https://captchaai.com/dashboard") - elif error in BALANCE_ERRORS: - print(f"[!] Balance error: {error}") - print(" Top up your account at https://captchaai.com") - elif error in INPUT_ERRORS: - print(f"[!] Input error: {error}") - print(" Verify your gt (captcha_id) and page URL are correct.") - elif error in PROXY_ERRORS: - print(f"[!] Proxy error: {error}") - print(" Check your proxy configuration or try a different proxy.") - else: - print(f"[!] Submission failed: {error}") - sys.exit(1) - - task_id = data["request"] - print(f"[+] Task submitted. ID: {task_id}") - return task_id - - -def poll_result(task_id: str) -> dict: - """Poll for the CAPTCHA solution with timeout and retry logic.""" - print("[*] Waiting 15s before first poll...") - time.sleep(15) - - params = { - "key": API_KEY, - "action": "get", - "id": task_id, - "json": "1", - } - - elapsed = 15 - attempt = 0 - backoff = POLL_INTERVAL - - while elapsed < MAX_TIMEOUT: - attempt += 1 - print(f"[*] Polling for result (attempt {attempt})...") - - try: - resp = requests.get(RESULT_URL, params=params, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during polling: {exc}") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - data = resp.json() - - if data.get("status") == 1: - # The request field contains a JSON string with the 5 GeeTest v4 values - solution = data["request"] - if isinstance(solution, str): - solution = json.loads(solution) - return solution - - error = data.get("request", "") - if error == "CAPCHA_NOT_READY": - print(f"[*] Not ready yet, waiting {POLL_INTERVAL}s...") - time.sleep(POLL_INTERVAL) - elapsed += POLL_INTERVAL - backoff = POLL_INTERVAL - continue - - if error in TRANSIENT_ERRORS: - print(f"[!] Transient error: {error}, retrying in {backoff}s...") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - if error in SOLVE_ERRORS: - print(f"[!] Solve error: {error}") - print(" The CAPTCHA could not be solved. Verify parameters and retry.") - sys.exit(1) - - print(f"[!] Unexpected error: {error}") - sys.exit(1) - - print(f"[!] Timeout: no solution received within {MAX_TIMEOUT} seconds.") - sys.exit(1) - - -def main() -> None: - validate_config() - task_id = submit_task() - solution = poll_result(task_id) - print("[+] Solved!") - print(f"[+] captcha_id: {solution['captcha_id']}") - print(f"[+] lot_number: {solution['lot_number']}") - print(f"[+] pass_token: {solution['pass_token']}") - print(f"[+] gen_time: {solution['gen_time']}") - print(f"[+] captcha_output: {solution['captcha_output']}") - print() - print("Next step: submit these five values to the site's") - print("GeeTest v4 verification endpoint.") - - -if __name__ == "__main__": - main() diff --git a/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile b/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile deleted file mode 100644 index 05a677e..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source "https://rubygems.org" -# No external gems needed — uses Ruby stdlib (net/http, json, uri) diff --git a/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb b/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb deleted file mode 100644 index 6627d61..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb +++ /dev/null @@ -1,191 +0,0 @@ -# Solve GeeTest v4 using the CaptchaAI API. -# -# Usage: -# ruby solve.rb - -require "net/http" -require "json" -require "uri" - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -AUTH_ERRORS = %w[ERROR_WRONG_USER_KEY ERROR_KEY_DOES_NOT_EXIST IP_BANNED].freeze -BALANCE_ERRORS = %w[ERROR_ZERO_BALANCE].freeze -INPUT_ERRORS = %w[ERROR_PAGEURL ERROR_WRONG_GOOGLEKEY ERROR_BAD_PARAMETERS ERROR_BAD_TOKEN_OR_PAGEURL].freeze -TRANSIENT_ERRORS = %w[ERROR_SERVER_ERROR ERROR_INTERNAL_SERVER_ERROR].freeze -SOLVE_ERRORS = %w[ERROR_CAPTCHA_UNSOLVABLE].freeze -PROXY_ERRORS = %w[ERROR_BAD_PROXY ERROR_PROXY_CONNECTION_FAILED].freeze - -def load_env(path) - env = {} - return env unless File.exist?(path) - File.readlines(path).each do |line| - line = line.strip - next if line.empty? || line.start_with?("#") - key, value = line.split("=", 2) - env[key.strip] = value&.strip || "" - end - env -end - -def get_env(env, key, fallback = "") - v = env[key] - return v if v && !v.empty? - v = ENV[key] - return v if v && !v.empty? - fallback -end - -env = load_env(File.join(__dir__, "..", ".env")) -api_key = get_env(env, "CAPTCHAAI_API_KEY") -gt = get_env(env, "CAPTCHA_GT") -pageurl = get_env(env, "CAPTCHA_PAGEURL") -poll_interval = get_env(env, "POLL_INTERVAL", "5").to_i -max_timeout = get_env(env, "MAX_TIMEOUT", "120").to_i - -# Validate -if api_key.empty? || api_key == "YOUR_API_KEY" - puts "[!] ERROR: CAPTCHAAI_API_KEY is not set." - puts " Copy .env.example to .env and add your real API key." - exit 1 -end -if gt.empty? || gt == "YOUR_CAPTCHA_ID" - puts "[!] ERROR: CAPTCHA_GT is not set." - puts " Find the captcha_id in the page source or GeeTest v4 initialization call." - exit 1 -end -if pageurl.empty? || pageurl == "https://example.com" - puts "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - puts " Make sure it points to the actual target page." -end - -def handle_error(error) - if AUTH_ERRORS.include?(error) - puts "[!] Authentication error: #{error}" - puts " Check your API key at https://captchaai.com/dashboard" - elsif BALANCE_ERRORS.include?(error) - puts "[!] Balance error: #{error}" - puts " Top up your account at https://captchaai.com" - elsif INPUT_ERRORS.include?(error) - puts "[!] Input error: #{error}" - puts " Verify your gt (captcha_id) and page URL are correct." - elsif PROXY_ERRORS.include?(error) - puts "[!] Proxy error: #{error}" - puts " Check your proxy configuration or try a different proxy." - else - puts "[!] Submission failed: #{error}" - end -end - -def http_get(url_str) - uri = URI(url_str) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.open_timeout = 30 - http.read_timeout = 30 - response = http.get("#{uri.path}?#{uri.query}") - JSON.parse(response.body) -end - -# Submit task -puts "[*] Submitting GeeTest v4 task..." -submit_params = { - key: api_key, - method: "geetest", - gt: gt, - pageurl: pageurl, - version: "4", - json: "1" -} -params = URI.encode_www_form(submit_params) - -begin - submit_data = http_get("#{SUBMIT_URL}?#{params}") -rescue StandardError => e - puts "[!] Network error during submission: #{e.message}" - exit 1 -end - -unless submit_data["status"] == 1 - handle_error(submit_data["request"] || "UNKNOWN_ERROR") - exit 1 -end - -task_id = submit_data["request"] -puts "[+] Task submitted. ID: #{task_id}" - -# Poll for result -puts "[*] Waiting 15s before first poll..." -sleep 15 - -elapsed = 15 -attempt = 0 -backoff = poll_interval - -while elapsed < max_timeout - attempt += 1 - puts "[*] Polling for result (attempt #{attempt})..." - - poll_params = URI.encode_www_form( - key: api_key, - action: "get", - id: task_id, - json: "1" - ) - - begin - result_data = http_get("#{RESULT_URL}?#{poll_params}") - rescue StandardError => e - puts "[!] Network error during polling: #{e.message}" - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if result_data["status"] == 1 - # The request field contains a JSON string or object with the 5 GeeTest v4 values - solution = result_data["request"] - solution = JSON.parse(solution) if solution.is_a?(String) - puts "[+] Solved!" - puts "[+] captcha_id: #{solution['captcha_id']}" - puts "[+] lot_number: #{solution['lot_number']}" - puts "[+] pass_token: #{solution['pass_token']}" - puts "[+] gen_time: #{solution['gen_time']}" - puts "[+] captcha_output: #{solution['captcha_output']}" - puts - puts "Next step: submit these five values to the site's" - puts "GeeTest v4 verification endpoint." - exit 0 - end - - error = result_data["request"] || "" - if error == "CAPCHA_NOT_READY" - puts "[*] Not ready yet, waiting #{poll_interval}s..." - sleep poll_interval - elapsed += poll_interval - backoff = poll_interval - next - end - - if TRANSIENT_ERRORS.include?(error) - puts "[!] Transient error: #{error}, retrying in #{backoff}s..." - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if SOLVE_ERRORS.include?(error) - puts "[!] Solve error: #{error}" - puts " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - end - - puts "[!] Unexpected error: #{error}" - exit 1 -end - -puts "[!] Timeout: no solution received within #{max_timeout} seconds." -exit 1 diff --git a/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml b/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml deleted file mode 100644 index 8c10bc5..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "captchaai-geetest-v4-example" -version = "1.0.0" -edition = "2021" - -[dependencies] -ureq = "2" -serde_json = "1" -urlencoding = "2" diff --git a/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs b/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs deleted file mode 100644 index 06d2f68..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs +++ /dev/null @@ -1,260 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// cargo run - -use std::collections::HashMap; -use std::fs; -use std::thread; -use std::time::Duration; - -const SUBMIT_URL: &str = "https://ocr.captchaai.com/in.php"; -const RESULT_URL: &str = "https://ocr.captchaai.com/res.php"; - -fn load_env(path: &str) -> HashMap { - let mut env = HashMap::new(); - if let Ok(content) = fs::read_to_string(path) { - for line in content.lines() { - let trimmed = line.trim(); - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - if let Some((key, value)) = trimmed.split_once('=') { - env.insert(key.trim().to_string(), value.trim().to_string()); - } - } - } - env -} - -fn get_env(env: &HashMap, key: &str, fallback: &str) -> String { - if let Some(v) = env.get(key) { - if !v.is_empty() { - return v.clone(); - } - } - if let Ok(v) = std::env::var(key) { - if !v.is_empty() { - return v; - } - } - fallback.to_string() -} - -fn json_str(json: &str, key: &str) -> String { - let pattern = format!("\"{}\":\"", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - if let Some(end) = json[start..].find('"') { - return json[start..start + end].to_string(); - } - } - String::new() -} - -fn json_int(json: &str, key: &str) -> i32 { - let pattern = format!("\"{}\":", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - let num_str: String = json[start..] - .chars() - .take_while(|c| c.is_ascii_digit() || *c == '-') - .collect(); - return num_str.parse().unwrap_or(0); - } - 0 -} - -fn extract_request_json(json: &str) -> String { - let pattern = "\"request\":"; - if let Some(idx) = json.find(pattern) { - let start = idx + pattern.len(); - let rest = json[start..].trim_start(); - if rest.starts_with('"') { - // JSON string — find closing quote, handle escapes - let inner = &rest[1..]; - let mut end = 0; - let chars: Vec = inner.chars().collect(); - while end < chars.len() { - if chars[end] == '\\' { end += 2; continue; } - if chars[end] == '"' { break; } - end += 1; - } - let s: String = inner.chars().take(end).collect(); - return s.replace("\\\"", "\"").replace("\\\\", "\\"); - } else if rest.starts_with('{') { - // JSON object — find matching brace - let mut depth = 0; - let mut end = 0; - for (i, c) in rest.char_indices() { - if c == '{' { depth += 1; } - else if c == '}' { depth -= 1; if depth == 0 { end = i + 1; break; } } - } - return rest[..end].to_string(); - } - } - String::new() -} - -fn handle_error(error: &str) { - let auth = ["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]; - let balance = ["ERROR_ZERO_BALANCE"]; - let input = ["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]; - let proxy = ["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]; - - if auth.contains(&error) { - println!("[!] Authentication error: {}", error); - println!(" Check your API key at https://captchaai.com/dashboard"); - } else if balance.contains(&error) { - println!("[!] Balance error: {}", error); - println!(" Top up your account at https://captchaai.com"); - } else if input.contains(&error) { - println!("[!] Input error: {}", error); - println!(" Verify your gt (captcha_id) and page URL are correct."); - } else if proxy.contains(&error) { - println!("[!] Proxy error: {}", error); - println!(" Check your proxy configuration or try a different proxy."); - } else { - println!("[!] Submission failed: {}", error); - } -} - -fn main() { - let env = load_env("../.env"); - let api_key = get_env(&env, "CAPTCHAAI_API_KEY", ""); - let gt = get_env(&env, "CAPTCHA_GT", ""); - let pageurl = get_env(&env, "CAPTCHA_PAGEURL", ""); - let poll_interval: u64 = get_env(&env, "POLL_INTERVAL", "5").parse().unwrap_or(5); - let max_timeout: u64 = get_env(&env, "MAX_TIMEOUT", "120").parse().unwrap_or(120); - - // Validate - if api_key.is_empty() || api_key == "YOUR_API_KEY" { - println!("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - println!(" Copy .env.example to .env and add your real API key."); - std::process::exit(1); - } - if gt.is_empty() || gt == "YOUR_CAPTCHA_ID" { - println!("[!] ERROR: CAPTCHA_GT is not set."); - println!(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - std::process::exit(1); - } - if pageurl.is_empty() || pageurl == "https://example.com" { - println!("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - println!(" Make sure it points to the actual target page."); - } - - // Submit task - println!("[*] Submitting GeeTest v4 task..."); - let submit_url = format!( - "{}?key={}&method=geetest>={}&pageurl={}&version=4&json=1", - SUBMIT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(>), - urlencoding::encode(&pageurl) - ); - - let submit_resp = match ureq::get(&submit_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during submission: {}", e); - std::process::exit(1); - } - }; - - let submit_status = json_int(&submit_resp, "status"); - let submit_request = json_str(&submit_resp, "request"); - - if submit_status != 1 { - handle_error(&submit_request); - std::process::exit(1); - } - - let task_id = submit_request; - println!("[+] Task submitted. ID: {}", task_id); - - // Poll for result - println!("[*] Waiting 15s before first poll..."); - thread::sleep(Duration::from_secs(15)); - - let mut elapsed: u64 = 15; - let mut attempt = 0; - let mut backoff = poll_interval; - - let transient = ["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]; - let solve = ["ERROR_CAPTCHA_UNSOLVABLE"]; - - while elapsed < max_timeout { - attempt += 1; - println!("[*] Polling for result (attempt {})...", attempt); - - let poll_url = format!( - "{}?key={}&action=get&id={}&json=1", - RESULT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&task_id) - ); - - let result_resp = match ureq::get(&poll_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during polling: {}", e); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - }; - - let status = json_int(&result_resp, "status"); - - if status == 1 { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - let solution_json = extract_request_json(&result_resp); - let captcha_id = json_str(&solution_json, "captcha_id"); - let lot_number = json_str(&solution_json, "lot_number"); - let pass_token = json_str(&solution_json, "pass_token"); - let gen_time = json_str(&solution_json, "gen_time"); - let captcha_output = json_str(&solution_json, "captcha_output"); - println!("[+] Solved!"); - println!("[+] captcha_id: {}", captcha_id); - println!("[+] lot_number: {}", lot_number); - println!("[+] pass_token: {}", pass_token); - println!("[+] gen_time: {}", gen_time); - println!("[+] captcha_output: {}", captcha_output); - println!(); - println!("Next step: submit these five values to the site's"); - println!("GeeTest v4 verification endpoint."); - return; - } - - let request = json_str(&result_resp, "request"); - - if request == "CAPCHA_NOT_READY" { - println!("[*] Not ready yet, waiting {}s...", poll_interval); - thread::sleep(Duration::from_secs(poll_interval)); - elapsed += poll_interval; - backoff = poll_interval; - continue; - } - - if transient.contains(&request.as_str()) { - println!("[!] Transient error: {}, retrying in {}s...", request, backoff); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - - if solve.contains(&request.as_str()) { - println!("[!] Solve error: {}", request); - println!(" The CAPTCHA could not be solved. Verify parameters and retry."); - std::process::exit(1); - } - - println!("[!] Unexpected error: {}", request); - std::process::exit(1); - } - - println!("[!] Timeout: no solution received within {} seconds.", max_timeout); - std::process::exit(1); -} diff --git a/articles/how-to-solve-hcaptcha-using-api/.env.example b/articles/how-to-solve-hcaptcha-using-api/.env.example deleted file mode 100644 index e6ff2ad..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# CaptchaAI API credentials -# Get your API key from https://captchaai.com/dashboard -CAPTCHAAI_API_KEY=YOUR_API_KEY - -# Target page configuration -# hCaptcha sitekey from the target page -CAPTCHA_SITEKEY=YOUR_SITE_KEY -# Full URL of the page -CAPTCHA_PAGEURL=https://example.com/login - -# Polling configuration (optional) -POLL_INTERVAL=5 -MAX_TIMEOUT=120 diff --git a/articles/how-to-solve-hcaptcha-using-api/.gitignore b/articles/how-to-solve-hcaptcha-using-api/.gitignore deleted file mode 100644 index e9504be..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -.env -__pycache__/ -*.pyc -node_modules/ -vendor/ -composer.lock -package-lock.json -.DS_Store -Thumbs.db -# Go -go.sum -# Java -*.class -# C# -bin/ -obj/ -# Ruby -Gemfile.lock -# Rust -target/ diff --git a/articles/how-to-solve-hcaptcha-using-api/README.md b/articles/how-to-solve-hcaptcha-using-api/README.md deleted file mode 100644 index 6d2b694..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# hCaptcha — CaptchaAI Example Pack - -Full working example for solving hCaptcha using the CaptchaAI API. - -**Languages:** Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash - -## Related article - -This example accompanies the blog article: -**[How to Solve hCaptcha Using API](https://blog.captchaai.com/how-to-solve-hcaptcha-using-api)** - -## Prerequisites - -- A CaptchaAI account with API key ([get one here](https://captchaai.com)) -- A target page with hCaptcha for testing -- One or more of: Python 3.8+, Node.js 16+, PHP 8.0+, Go 1.21+, Java 11+, .NET 8+, Ruby 3.0+, Rust 1.70+, Kotlin 1.9+, or Bash with curl and jq - -## Setup - -1. Clone the repository: - ```bash - git clone https://github.com/CaptchaAI/CaptchaAI-Examples.git - cd CaptchaAI-Examples/articles/how-to-solve-hcaptcha-using-api - ``` - -2. Copy the environment file and add your credentials: - ```bash - cp .env.example .env - ``` - -3. Edit `.env` with your API key and target page details. - -4. Follow the language-specific setup below. - -### Python - -```bash -cd python -pip install -r requirements.txt -python solve.py -``` - -### Node.js - -```bash -cd node -npm install -node solve.js -``` - -### PHP - -```bash -cd php -composer install -php solve.php -``` - -### Go - -```bash -cd go -go run solve.go -``` - -### Java - -```bash -cd java -javac Solve.java -java Solve -``` - -### C# - -```bash -cd csharp -dotnet run -``` - -### Ruby - -```bash -cd ruby -bundle install # optional — uses stdlib only -ruby solve.rb -``` - -### Rust - -```bash -cd rust -cargo run -``` - -### Kotlin - -```bash -cd kotlin -kotlinc solve.kt -include-runtime -d solve.jar -java -jar solve.jar -``` - -### Bash - -```bash -cd bash -chmod +x solve.sh -bash solve.sh -``` - -## Environment variables - -| Variable | Description | -|---|---| -| `CAPTCHAAI_API_KEY` | Your CaptchaAI API key | -| `CAPTCHA_SITEKEY` | hCaptcha sitekey from the target page | -| `CAPTCHA_PAGEURL` | Full URL of the target page | -| `POLL_INTERVAL` | Seconds between polls (default: 5) | -| `MAX_TIMEOUT` | Maximum wait in seconds (default: 120) | diff --git a/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh b/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh deleted file mode 100644 index 2534283..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env bash -# Solve hCaptcha using the CaptchaAI API. -# -# Usage: -# chmod +x solve.sh -# bash solve.sh - -set -euo pipefail - -SUBMIT_URL="https://ocr.captchaai.com/in.php" -RESULT_URL="https://ocr.captchaai.com/res.php" - -# Load .env -ENV_FILE="$(dirname "$0")/../.env" -if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - source "$ENV_FILE" - set +a -fi - -API_KEY="${CAPTCHAAI_API_KEY:-}" -SITEKEY="${CAPTCHA_SITEKEY:-}" -PAGEURL="${CAPTCHA_PAGEURL:-}" -POLL_INTERVAL="${POLL_INTERVAL:-5}" -MAX_TIMEOUT="${MAX_TIMEOUT:-120}" - -# Validate -if [[ -z "$API_KEY" || "$API_KEY" == "YOUR_API_KEY" ]]; then - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set." - echo " Copy .env.example to .env and add your real API key." - exit 1 -fi -if [[ -z "$SITEKEY" || "$SITEKEY" == "YOUR_SITE_KEY" ]]; then - echo "[!] ERROR: CAPTCHA_SITEKEY is not set." - echo " Add the hCaptcha sitekey from your target page to .env" - exit 1 -fi -if [[ -z "$PAGEURL" || "$PAGEURL" == "https://example.com/login" ]]; then - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - echo " Make sure it points to the actual target page." -fi - -# JSON helpers -json_str() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\"\\K[^\"]*" || echo "" -} -json_int() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\\K[0-9]+" || echo "0" -} - -# Error handler -handle_error() { - local error="$1" - case "$error" in - ERROR_WRONG_USER_KEY|ERROR_KEY_DOES_NOT_EXIST|IP_BANNED) - echo "[!] Authentication error: $error" - echo " Check your API key at https://captchaai.com/dashboard" - ;; - ERROR_ZERO_BALANCE) - echo "[!] Balance error: $error" - echo " Top up your account at https://captchaai.com" - ;; - ERROR_PAGEURL|ERROR_WRONG_GOOGLEKEY|ERROR_BAD_PARAMETERS|ERROR_BAD_TOKEN_OR_PAGEURL) - echo "[!] Input error: $error" - echo " Verify your sitekey and page URL are correct." - ;; - ERROR_BAD_PROXY|ERROR_PROXY_CONNECTION_FAILED) - echo "[!] Proxy error: $error" - echo " Check your proxy configuration or try a different proxy." - ;; - *) - echo "[!] Submission failed: $error" - ;; - esac -} - -# Submit task -echo "[*] Submitting hCaptcha task..." -ENCODED_KEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$API_KEY'))" 2>/dev/null || echo "$API_KEY") -ENCODED_SITEKEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$SITEKEY'))" 2>/dev/null || echo "$SITEKEY") -ENCODED_PAGEURL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAGEURL'))" 2>/dev/null || echo "$PAGEURL") - -SUBMIT_RESP=$(curl -sS --max-time 30 \ - "${SUBMIT_URL}?key=${ENCODED_KEY}&method=hcaptcha&sitekey=${ENCODED_SITEKEY}&pageurl=${ENCODED_PAGEURL}&json=1") - -if [[ -z "$SUBMIT_RESP" ]]; then - echo "[!] Network error during submission." - exit 1 -fi - -SUBMIT_STATUS=$(json_int "$SUBMIT_RESP" "status") -SUBMIT_REQUEST=$(json_str "$SUBMIT_RESP" "request") - -if [[ "$SUBMIT_STATUS" -ne 1 ]]; then - handle_error "$SUBMIT_REQUEST" - exit 1 -fi - -TASK_ID="$SUBMIT_REQUEST" -echo "[+] Task submitted. ID: $TASK_ID" - -# Poll for result -echo "[*] Waiting 15s before first poll..." -sleep 15 - -ELAPSED=15 -ATTEMPT=0 -BACKOFF="$POLL_INTERVAL" - -while [[ "$ELAPSED" -lt "$MAX_TIMEOUT" ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "[*] Polling for result (attempt $ATTEMPT)..." - - POLL_RESP=$(curl -sS --max-time 30 \ - "${RESULT_URL}?key=${ENCODED_KEY}&action=get&id=${TASK_ID}&json=1" 2>/dev/null || echo "") - - if [[ -z "$POLL_RESP" ]]; then - echo "[!] Network error during polling." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - fi - - STATUS=$(json_int "$POLL_RESP" "status") - REQUEST=$(json_str "$POLL_RESP" "request") - - if [[ "$STATUS" -eq 1 ]]; then - DISPLAY="${REQUEST:0:50}" - echo "[+] Solved! Token: ${DISPLAY}..." - echo "[+] Full token length: ${#REQUEST} characters" - echo - echo "Next step: inject this token into the target page's" - echo "h-captcha-response hidden field and submit the form." - exit 0 - fi - - if [[ "$REQUEST" == "CAPCHA_NOT_READY" ]]; then - echo "[*] Not ready yet, waiting ${POLL_INTERVAL}s..." - sleep "$POLL_INTERVAL" - ELAPSED=$((ELAPSED + POLL_INTERVAL)) - BACKOFF="$POLL_INTERVAL" - continue - fi - - case "$REQUEST" in - ERROR_SERVER_ERROR|ERROR_INTERNAL_SERVER_ERROR) - echo "[!] Transient error: $REQUEST, retrying in ${BACKOFF}s..." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - ;; - ERROR_CAPTCHA_UNSOLVABLE) - echo "[!] Solve error: $REQUEST" - echo " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - ;; - esac - - echo "[!] Unexpected error: $REQUEST" - exit 1 -done - -echo "[!] Timeout: no solution received within $MAX_TIMEOUT seconds." -exit 1 diff --git a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs b/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs deleted file mode 100644 index c71da03..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// dotnet run - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; - -const string SubmitUrl = "https://ocr.captchaai.com/in.php"; -const string ResultUrl = "https://ocr.captchaai.com/res.php"; - -var authErrors = new HashSet { "ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED" }; -var balanceErrors = new HashSet { "ERROR_ZERO_BALANCE" }; -var inputErrors = new HashSet { "ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL" }; -var transientErrors = new HashSet { "ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR" }; -var solveErrors = new HashSet { "ERROR_CAPTCHA_UNSOLVABLE" }; -var proxyErrors = new HashSet { "ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED" }; - -var env = LoadEnv(Path.Combine("..", ".env")); -string apiKey = GetEnv(env, "CAPTCHAAI_API_KEY", ""); -string sitekey = GetEnv(env, "CAPTCHA_SITEKEY", ""); -string pageurl = GetEnv(env, "CAPTCHA_PAGEURL", ""); -int pollInterval = int.Parse(GetEnv(env, "POLL_INTERVAL", "5")); -int maxTimeout = int.Parse(GetEnv(env, "MAX_TIMEOUT", "120")); - -// Validate -if (string.IsNullOrEmpty(apiKey) || apiKey == "YOUR_API_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - Console.WriteLine(" Copy .env.example to .env and add your real API key."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(sitekey) || sitekey == "YOUR_SITE_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHA_SITEKEY is not set."); - Console.WriteLine(" Add the hCaptcha sitekey from your target page to .env"); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(pageurl) || pageurl == "https://example.com/login") -{ - Console.WriteLine("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - Console.WriteLine(" Make sure it points to the actual target page."); -} - -using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; - -// Submit task -Console.WriteLine("[*] Submitting hCaptcha task..."); -var submitQuery = $"key={Uri.EscapeDataString(apiKey)}&method=hcaptcha&sitekey={Uri.EscapeDataString(sitekey)}&pageurl={Uri.EscapeDataString(pageurl)}&json=1"; - -string submitBody; -try -{ - submitBody = await client.GetStringAsync($"{SubmitUrl}?{submitQuery}"); -} -catch (Exception ex) -{ - Console.WriteLine($"[!] Network error during submission: {ex.Message}"); - Environment.Exit(1); - return; -} - -using var submitDoc = JsonDocument.Parse(submitBody); -int submitStatus = submitDoc.RootElement.GetProperty("status").GetInt32(); -string submitRequest = submitDoc.RootElement.GetProperty("request").GetString() ?? ""; - -if (submitStatus != 1) -{ - HandleError(submitRequest, authErrors, balanceErrors, inputErrors, proxyErrors); - Environment.Exit(1); -} - -string taskId = submitRequest; -Console.WriteLine($"[+] Task submitted. ID: {taskId}"); - -// Poll for result -Console.WriteLine("[*] Waiting 15s before first poll..."); -await Task.Delay(15000); - -int elapsed = 15; -int attempt = 0; -int backoff = pollInterval; - -while (elapsed < maxTimeout) -{ - attempt++; - Console.WriteLine($"[*] Polling for result (attempt {attempt})..."); - - var pollQuery = $"key={Uri.EscapeDataString(apiKey)}&action=get&id={Uri.EscapeDataString(taskId)}&json=1"; - - string resultBody; - try - { - resultBody = await client.GetStringAsync($"{ResultUrl}?{pollQuery}"); - } - catch (Exception ex) - { - Console.WriteLine($"[!] Network error during polling: {ex.Message}"); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - using var resultDoc = JsonDocument.Parse(resultBody); - int status = resultDoc.RootElement.GetProperty("status").GetInt32(); - string request = resultDoc.RootElement.GetProperty("request").GetString() ?? ""; - - if (status == 1) - { - string display = request.Length > 50 ? request[..50] : request; - Console.WriteLine($"[+] Solved! Token: {display}..."); - Console.WriteLine($"[+] Full token length: {request.Length} characters"); - Console.WriteLine(); - Console.WriteLine("Next step: inject this token into the target page's"); - Console.WriteLine("h-captcha-response hidden field and submit the form."); - return; - } - - if (request == "CAPCHA_NOT_READY") - { - Console.WriteLine($"[*] Not ready yet, waiting {pollInterval}s..."); - await Task.Delay(pollInterval * 1000); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (transientErrors.Contains(request)) - { - Console.WriteLine($"[!] Transient error: {request}, retrying in {backoff}s..."); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - if (solveErrors.Contains(request)) - { - Console.WriteLine($"[!] Solve error: {request}"); - Console.WriteLine(" The CAPTCHA could not be solved. Verify parameters and retry."); - Environment.Exit(1); - } - - Console.WriteLine($"[!] Unexpected error: {request}"); - Environment.Exit(1); -} - -Console.WriteLine($"[!] Timeout: no solution received within {maxTimeout} seconds."); -Environment.Exit(1); - -static Dictionary LoadEnv(string path) -{ - var dict = new Dictionary(); - if (!File.Exists(path)) return dict; - foreach (var line in File.ReadAllLines(path)) - { - var trimmed = line.Trim(); - if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith('#')) continue; - var eq = trimmed.IndexOf('='); - if (eq > 0) - dict[trimmed[..eq].Trim()] = trimmed[(eq + 1)..].Trim(); - } - return dict; -} - -static string GetEnv(Dictionary env, string key, string fallback) -{ - if (env.TryGetValue(key, out var v) && !string.IsNullOrEmpty(v)) return v; - v = Environment.GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(v)) return v; - return fallback; -} - -static void HandleError(string error, HashSet auth, HashSet balance, HashSet input, HashSet proxy) -{ - if (auth.Contains(error)) - { - Console.WriteLine($"[!] Authentication error: {error}"); - Console.WriteLine(" Check your API key at https://captchaai.com/dashboard"); - } - else if (balance.Contains(error)) - { - Console.WriteLine($"[!] Balance error: {error}"); - Console.WriteLine(" Top up your account at https://captchaai.com"); - } - else if (input.Contains(error)) - { - Console.WriteLine($"[!] Input error: {error}"); - Console.WriteLine(" Verify your sitekey and page URL are correct."); - } - else if (proxy.Contains(error)) - { - Console.WriteLine($"[!] Proxy error: {error}"); - Console.WriteLine(" Check your proxy configuration or try a different proxy."); - } - else - { - Console.WriteLine($"[!] Submission failed: {error}"); - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj b/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj deleted file mode 100644 index dd4b568..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - Exe - net8.0 - - diff --git a/articles/how-to-solve-hcaptcha-using-api/go/go.mod b/articles/how-to-solve-hcaptcha-using-api/go/go.mod deleted file mode 100644 index 9d0e8ad..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module captchaai-hcaptcha-example - -go 1.21 diff --git a/articles/how-to-solve-hcaptcha-using-api/go/solve.go b/articles/how-to-solve-hcaptcha-using-api/go/solve.go deleted file mode 100644 index 40b000a..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/go/solve.go +++ /dev/null @@ -1,238 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// go run solve.go - -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "time" -) - -const submitURL = "https://ocr.captchaai.com/in.php" -const resultURL = "https://ocr.captchaai.com/res.php" - -var authErrors = map[string]bool{"ERROR_WRONG_USER_KEY": true, "ERROR_KEY_DOES_NOT_EXIST": true, "IP_BANNED": true} -var balanceErrors = map[string]bool{"ERROR_ZERO_BALANCE": true} -var inputErrors = map[string]bool{"ERROR_PAGEURL": true, "ERROR_WRONG_GOOGLEKEY": true, "ERROR_BAD_PARAMETERS": true, "ERROR_BAD_TOKEN_OR_PAGEURL": true} -var transientErrors = map[string]bool{"ERROR_SERVER_ERROR": true, "ERROR_INTERNAL_SERVER_ERROR": true} -var solveErrors = map[string]bool{"ERROR_CAPTCHA_UNSOLVABLE": true} -var proxyErrors = map[string]bool{"ERROR_BAD_PROXY": true, "ERROR_PROXY_CONNECTION_FAILED": true} - -type apiResponse struct { - Status int `json:"status"` - Request any `json:"request"` -} - -func requestValue(value any) string { - switch v := value.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func loadEnv() map[string]string { - path := filepath.Join("..", ".env") - env := make(map[string]string) - f, err := os.Open(path) - if err != nil { - return env - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - env[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) - } - } - - return env -} - -func getEnv(env map[string]string, key, fallback string) string { - if value, ok := env[key]; ok && value != "" { - return value - } - if value := os.Getenv(key); value != "" { - return value - } - return fallback -} - -func main() { - env := loadEnv() - apiKey := getEnv(env, "CAPTCHAAI_API_KEY", "") - sitekey := getEnv(env, "CAPTCHA_SITEKEY", "") - pageurl := getEnv(env, "CAPTCHA_PAGEURL", "") - pollInterval, _ := strconv.Atoi(getEnv(env, "POLL_INTERVAL", "5")) - maxTimeout, _ := strconv.Atoi(getEnv(env, "MAX_TIMEOUT", "120")) - - if apiKey == "" || apiKey == "YOUR_API_KEY" { - fmt.Println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - fmt.Println(" Copy .env.example to .env and add your real API key.") - os.Exit(1) - } - if sitekey == "" || sitekey == "YOUR_SITE_KEY" { - fmt.Println("[!] ERROR: CAPTCHA_SITEKEY is not set.") - fmt.Println(" Add the hCaptcha sitekey from your target page to .env") - os.Exit(1) - } - if pageurl == "" || pageurl == "https://example.com/login" { - fmt.Println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - fmt.Println(" Make sure it points to the actual target page.") - } - - client := &http.Client{Timeout: 30 * time.Second} - - // Submit task - fmt.Println("[*] Submitting hCaptcha task...") - params := url.Values{ - "key": {apiKey}, - "method": {"hcaptcha"}, - "sitekey": {sitekey}, - "pageurl": {pageurl}, - "json": {"1"}, - } - - resp, err := client.Get(submitURL + "?" + params.Encode()) - if err != nil { - fmt.Printf("[!] Network error during submission: %v\n", err) - os.Exit(1) - } - defer resp.Body.Close() - - body, _ := io.ReadAll(resp.Body) - var submitResp apiResponse - json.Unmarshal(body, &submitResp) - - if submitResp.Status != 1 { - handleError(requestValue(submitResp.Request)) - os.Exit(1) - } - - taskID := requestValue(submitResp.Request) - fmt.Printf("[+] Task submitted. ID: %s\n", taskID) - - // Poll for result - fmt.Println("[*] Waiting 15s before first poll...") - time.Sleep(15 * time.Second) - - elapsed := 15 - attempt := 0 - backoff := pollInterval - - for elapsed < maxTimeout { - attempt++ - fmt.Printf("[*] Polling for result (attempt %d)...\n", attempt) - - pollParams := url.Values{ - "key": {apiKey}, - "action": {"get"}, - "id": {taskID}, - "json": {"1"}, - } - - resp, err := client.Get(resultURL + "?" + pollParams.Encode()) - if err != nil { - fmt.Printf("[!] Network error during polling: %v\n", err) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - body, _ := io.ReadAll(resp.Body) - resp.Body.Close() - var result apiResponse - json.Unmarshal(body, &result) - reqStr := requestValue(result.Request) - - if result.Status == 1 { - token := reqStr - display := token - if len(display) > 50 { - display = display[:50] - } - fmt.Printf("[+] Solved! Token: %s...\n", display) - fmt.Printf("[+] Full token length: %d characters\n", len(token)) - fmt.Println() - fmt.Println("Next step: inject this token into the target page's") - fmt.Println("h-captcha-response hidden field and submit the form.") - return - } - - if reqStr == "CAPCHA_NOT_READY" { - fmt.Printf("[*] Not ready yet, waiting %ds...\n", pollInterval) - time.Sleep(time.Duration(pollInterval) * time.Second) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if transientErrors[reqStr] { - fmt.Printf("[!] Transient error: %s, retrying in %ds...\n", reqStr, backoff) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - if solveErrors[reqStr] { - fmt.Printf("[!] Solve error: %s\n", reqStr) - fmt.Println(" The CAPTCHA could not be solved. Verify parameters and retry.") - os.Exit(1) - } - - fmt.Printf("[!] Unexpected error: %s\n", reqStr) - os.Exit(1) - } - - fmt.Printf("[!] Timeout: no solution received within %d seconds.\n", maxTimeout) - os.Exit(1) -} - -func handleError(errCode string) { - if authErrors[errCode] { - fmt.Printf("[!] Authentication error: %s\n", errCode) - fmt.Println(" Check your API key at https://captchaai.com/dashboard") - } else if balanceErrors[errCode] { - fmt.Printf("[!] Balance error: %s\n", errCode) - fmt.Println(" Top up your account at https://captchaai.com") - } else if inputErrors[errCode] { - fmt.Printf("[!] Input error: %s\n", errCode) - fmt.Println(" Verify your sitekey and page URL are correct.") - } else if proxyErrors[errCode] { - fmt.Printf("[!] Proxy error: %s\n", errCode) - fmt.Println(" Check your proxy configuration or try a different proxy.") - } else { - fmt.Printf("[!] Submission failed: %s\n", errCode) - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/java/Solve.java b/articles/how-to-solve-hcaptcha-using-api/java/Solve.java deleted file mode 100644 index 3f3eba9..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/java/Solve.java +++ /dev/null @@ -1,221 +0,0 @@ -import java.io.*; -import java.net.*; -import java.nio.file.*; -import java.util.*; - -/** - * Solve hCaptcha using the CaptchaAI API. - * - * Usage: - * javac Solve.java - * java Solve - */ -public class Solve { - static final String SUBMIT_URL = "https://ocr.captchaai.com/in.php"; - static final String RESULT_URL = "https://ocr.captchaai.com/res.php"; - - static final Set AUTH_ERRORS = Set.of("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"); - static final Set BALANCE_ERRORS = Set.of("ERROR_ZERO_BALANCE"); - static final Set INPUT_ERRORS = Set.of("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"); - static final Set TRANSIENT_ERRORS = Set.of("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"); - static final Set SOLVE_ERRORS = Set.of("ERROR_CAPTCHA_UNSOLVABLE"); - static final Set PROXY_ERRORS = Set.of("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"); - - static Map env = new HashMap<>(); - - public static void main(String[] args) throws Exception { - loadEnv(); - String apiKey = getEnv("CAPTCHAAI_API_KEY", ""); - String sitekey = getEnv("CAPTCHA_SITEKEY", ""); - String pageurl = getEnv("CAPTCHA_PAGEURL", ""); - int pollInterval = Integer.parseInt(getEnv("POLL_INTERVAL", "5")); - int maxTimeout = Integer.parseInt(getEnv("MAX_TIMEOUT", "120")); - - // Validate - if (apiKey.isEmpty() || apiKey.equals("YOUR_API_KEY")) { - System.out.println("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - System.out.println(" Copy .env.example to .env and add your real API key."); - System.exit(1); - } - if (sitekey.isEmpty() || sitekey.equals("YOUR_SITE_KEY")) { - System.out.println("[!] ERROR: CAPTCHA_SITEKEY is not set."); - System.out.println(" Add the hCaptcha sitekey from your target page to .env"); - System.exit(1); - } - if (pageurl.isEmpty() || pageurl.equals("https://example.com/login")) { - System.out.println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - System.out.println(" Make sure it points to the actual target page."); - } - - // Submit task - System.out.println("[*] Submitting hCaptcha task..."); - String submitParams = String.format( - "key=%s&method=hcaptcha&sitekey=%s&pageurl=%s&json=1", - enc(apiKey), enc(sitekey), enc(pageurl) - ); - - String submitResp = httpGet(SUBMIT_URL + "?" + submitParams); - int submitStatus = jsonInt(submitResp, "status"); - String submitRequest = jsonStr(submitResp, "request"); - - if (submitStatus != 1) { - handleError(submitRequest); - System.exit(1); - } - - String taskId = submitRequest; - System.out.println("[+] Task submitted. ID: " + taskId); - - // Poll for result - System.out.println("[*] Waiting 15s before first poll..."); - Thread.sleep(15000); - - int elapsed = 15; - int attempt = 0; - int backoff = pollInterval; - - while (elapsed < maxTimeout) { - attempt++; - System.out.println("[*] Polling for result (attempt " + attempt + ")..."); - - String pollParams = String.format( - "key=%s&action=get&id=%s&json=1", - enc(apiKey), enc(taskId) - ); - - String resultResp; - try { - resultResp = httpGet(RESULT_URL + "?" + pollParams); - } catch (Exception e) { - System.out.println("[!] Network error during polling: " + e.getMessage()); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - int status = jsonInt(resultResp, "status"); - String request = jsonStr(resultResp, "request"); - - if (status == 1) { - String display = request.length() > 50 ? request.substring(0, 50) : request; - System.out.println("[+] Solved! Token: " + display + "..."); - System.out.println("[+] Full token length: " + request.length() + " characters"); - System.out.println(); - System.out.println("Next step: inject this token into the target page's"); - System.out.println("h-captcha-response hidden field and submit the form."); - return; - } - - if ("CAPCHA_NOT_READY".equals(request)) { - System.out.println("[*] Not ready yet, waiting " + pollInterval + "s..."); - Thread.sleep(pollInterval * 1000L); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (TRANSIENT_ERRORS.contains(request)) { - System.out.println("[!] Transient error: " + request + ", retrying in " + backoff + "s..."); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.contains(request)) { - System.out.println("[!] Solve error: " + request); - System.out.println(" The CAPTCHA could not be solved. Verify parameters and retry."); - System.exit(1); - } - - System.out.println("[!] Unexpected error: " + request); - System.exit(1); - } - - System.out.println("[!] Timeout: no solution received within " + maxTimeout + " seconds."); - System.exit(1); - } - - static void loadEnv() { - try { - Path envPath = Paths.get("..", ".env"); - if (!Files.exists(envPath)) return; - for (String line : Files.readAllLines(envPath)) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) continue; - int eq = line.indexOf('='); - if (eq > 0) { - env.put(line.substring(0, eq).trim(), line.substring(eq + 1).trim()); - } - } - } catch (IOException ignored) {} - } - - static String getEnv(String key, String fallback) { - String v = env.get(key); - if (v != null && !v.isEmpty()) return v; - v = System.getenv(key); - if (v != null && !v.isEmpty()) return v; - return fallback; - } - - static String httpGet(String urlStr) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(30000); - conn.setReadTimeout(30000); - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) sb.append(line); - reader.close(); - return sb.toString(); - } - - static String enc(String s) throws Exception { - return URLEncoder.encode(s, "UTF-8"); - } - - static int jsonInt(String json, String key) { - String pattern = "\"" + key + "\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return 0; - int start = idx + pattern.length(); - StringBuilder sb = new StringBuilder(); - for (int i = start; i < json.length(); i++) { - char c = json.charAt(i); - if (c == ',' || c == '}') break; - if (c != ' ') sb.append(c); - } - try { return Integer.parseInt(sb.toString()); } catch (Exception e) { return 0; } - } - - static String jsonStr(String json, String key) { - String pattern = "\"" + key + "\":\""; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - int end = json.indexOf("\"", start); - if (end < 0) return ""; - return json.substring(start, end); - } - - static void handleError(String error) { - if (AUTH_ERRORS.contains(error)) { - System.out.println("[!] Authentication error: " + error); - System.out.println(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.contains(error)) { - System.out.println("[!] Balance error: " + error); - System.out.println(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.contains(error)) { - System.out.println("[!] Input error: " + error); - System.out.println(" Verify your sitekey and page URL are correct."); - } else if (PROXY_ERRORS.contains(error)) { - System.out.println("[!] Proxy error: " + error); - System.out.println(" Check your proxy configuration or try a different proxy."); - } else { - System.out.println("[!] Submission failed: " + error); - } - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt b/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt deleted file mode 100644 index 9c21623..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt +++ /dev/null @@ -1,213 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// kotlinc solve.kt -include-runtime -d solve.jar -// java -jar solve.jar - -import java.io.BufferedReader -import java.io.InputStreamReader -import java.net.HttpURLConnection -import java.net.URL -import java.net.URLEncoder -import java.io.File - -val SUBMIT_URL = "https://ocr.captchaai.com/in.php" -val RESULT_URL = "https://ocr.captchaai.com/res.php" - -val AUTH_ERRORS = setOf("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED") -val BALANCE_ERRORS = setOf("ERROR_ZERO_BALANCE") -val INPUT_ERRORS = setOf("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL") -val TRANSIENT_ERRORS = setOf("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR") -val SOLVE_ERRORS = setOf("ERROR_CAPTCHA_UNSOLVABLE") -val PROXY_ERRORS = setOf("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED") - -fun loadEnv(path: String): Map { - val env = mutableMapOf() - val file = File(path) - if (!file.exists()) return env - file.readLines().forEach { line -> - val trimmed = line.trim() - if (trimmed.isNotEmpty() && !trimmed.startsWith("#")) { - val eq = trimmed.indexOf('=') - if (eq > 0) { - env[trimmed.substring(0, eq).trim()] = trimmed.substring(eq + 1).trim() - } - } - } - return env -} - -fun getEnv(env: Map, key: String, fallback: String = ""): String { - val v = env[key] - if (!v.isNullOrEmpty()) return v - val sv = System.getenv(key) - if (!sv.isNullOrEmpty()) return sv - return fallback -} - -fun httpGet(urlStr: String): String { - val conn = URL(urlStr).openConnection() as HttpURLConnection - conn.connectTimeout = 30000 - conn.readTimeout = 30000 - val reader = BufferedReader(InputStreamReader(conn.inputStream)) - val result = reader.readText() - reader.close() - return result -} - -fun jsonStr(json: String, key: String): String { - val pattern = "\"$key\":\"" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val start = idx + pattern.length - val end = json.indexOf("\"", start) - if (end < 0) return "" - return json.substring(start, end) -} - -fun jsonInt(json: String, key: String): Int { - val pattern = "\"$key\":" - val idx = json.indexOf(pattern) - if (idx < 0) return 0 - val start = idx + pattern.length - val numStr = json.substring(start).takeWhile { it.isDigit() || it == '-' } - return numStr.toIntOrNull() ?: 0 -} - -fun handleError(error: String) { - when { - error in AUTH_ERRORS -> { - println("[!] Authentication error: $error") - println(" Check your API key at https://captchaai.com/dashboard") - } - error in BALANCE_ERRORS -> { - println("[!] Balance error: $error") - println(" Top up your account at https://captchaai.com") - } - error in INPUT_ERRORS -> { - println("[!] Input error: $error") - println(" Verify your sitekey and page URL are correct.") - } - error in PROXY_ERRORS -> { - println("[!] Proxy error: $error") - println(" Check your proxy configuration or try a different proxy.") - } - else -> println("[!] Submission failed: $error") - } -} - -fun enc(s: String) = URLEncoder.encode(s, "UTF-8") - -fun main() { - val env = loadEnv("../.env") - val apiKey = getEnv(env, "CAPTCHAAI_API_KEY") - val sitekey = getEnv(env, "CAPTCHA_SITEKEY") - val pageurl = getEnv(env, "CAPTCHA_PAGEURL") - val pollInterval = getEnv(env, "POLL_INTERVAL", "5").toInt() - val maxTimeout = getEnv(env, "MAX_TIMEOUT", "120").toInt() - - // Validate - if (apiKey.isEmpty() || apiKey == "YOUR_API_KEY") { - println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - println(" Copy .env.example to .env and add your real API key.") - System.exit(1) - } - if (sitekey.isEmpty() || sitekey == "YOUR_SITE_KEY") { - println("[!] ERROR: CAPTCHA_SITEKEY is not set.") - println(" Add the hCaptcha sitekey from your target page to .env") - System.exit(1) - } - if (pageurl.isEmpty() || pageurl == "https://example.com/login") { - println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - println(" Make sure it points to the actual target page.") - } - - // Submit task - println("[*] Submitting hCaptcha task...") - val submitParams = "key=${enc(apiKey)}&method=hcaptcha&sitekey=${enc(sitekey)}&pageurl=${enc(pageurl)}&json=1" - - val submitResp = try { - httpGet("$SUBMIT_URL?$submitParams") - } catch (e: Exception) { - println("[!] Network error during submission: ${e.message}") - System.exit(1) - return - } - - val submitStatus = jsonInt(submitResp, "status") - val submitRequest = jsonStr(submitResp, "request") - - if (submitStatus != 1) { - handleError(submitRequest) - System.exit(1) - } - - val taskId = submitRequest - println("[+] Task submitted. ID: $taskId") - - // Poll for result - println("[*] Waiting 15s before first poll...") - Thread.sleep(15000) - - var elapsed = 15 - var attempt = 0 - var backoff = pollInterval - - while (elapsed < maxTimeout) { - attempt++ - println("[*] Polling for result (attempt $attempt)...") - - val pollParams = "key=${enc(apiKey)}&action=get&id=${enc(taskId)}&json=1" - - val resultResp = try { - httpGet("$RESULT_URL?$pollParams") - } catch (e: Exception) { - println("[!] Network error during polling: ${e.message}") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - val status = jsonInt(resultResp, "status") - val request = jsonStr(resultResp, "request") - - if (status == 1) { - val display = if (request.length > 50) request.substring(0, 50) else request - println("[+] Solved! Token: $display...") - println("[+] Full token length: ${request.length} characters") - println() - println("Next step: inject this token into the target page's") - println("h-captcha-response hidden field and submit the form.") - return - } - - if (request == "CAPCHA_NOT_READY") { - println("[*] Not ready yet, waiting ${pollInterval}s...") - Thread.sleep(pollInterval * 1000L) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if (request in TRANSIENT_ERRORS) { - println("[!] Transient error: $request, retrying in ${backoff}s...") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - if (request in SOLVE_ERRORS) { - println("[!] Solve error: $request") - println(" The CAPTCHA could not be solved. Verify parameters and retry.") - System.exit(1) - } - - println("[!] Unexpected error: $request") - System.exit(1) - } - - println("[!] Timeout: no solution received within $maxTimeout seconds.") - System.exit(1) -} diff --git a/articles/how-to-solve-hcaptcha-using-api/node/package.json b/articles/how-to-solve-hcaptcha-using-api/node/package.json deleted file mode 100644 index afac6b5..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/node/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "captchaai-hcaptcha-example", - "version": "1.0.0", - "description": "Solve hCaptcha using CaptchaAI API", - "main": "solve.js", - "scripts": { - "start": "node solve.js" - }, - "dependencies": { - "axios": "^1.6.0", - "dotenv": "^16.3.0" - }, - "license": "MIT" -} diff --git a/articles/how-to-solve-hcaptcha-using-api/node/solve.js b/articles/how-to-solve-hcaptcha-using-api/node/solve.js deleted file mode 100644 index c0ce948..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/node/solve.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Solve hCaptcha using the CaptchaAI API. - * - * Usage: - * npm install - * cp ../.env.example ../.env // then edit with your credentials - * node solve.js - */ - -require("dotenv").config({ path: require("path").join(__dirname, "..", ".env") }); -const axios = require("axios"); - -const SUBMIT_URL = "https://ocr.captchaai.com/in.php"; -const RESULT_URL = "https://ocr.captchaai.com/res.php"; - -const API_KEY = process.env.CAPTCHAAI_API_KEY || ""; -const CAPTCHA_SITEKEY = process.env.CAPTCHA_SITEKEY || ""; -const CAPTCHA_PAGEURL = process.env.CAPTCHA_PAGEURL || ""; -const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || "5", 10); -const MAX_TIMEOUT = parseInt(process.env.MAX_TIMEOUT || "120", 10); - -const AUTH_ERRORS = new Set(["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]); -const BALANCE_ERRORS = new Set(["ERROR_ZERO_BALANCE"]); -const INPUT_ERRORS = new Set(["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]); -const TRANSIENT_ERRORS = new Set(["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]); -const SOLVE_ERRORS = new Set(["ERROR_CAPTCHA_UNSOLVABLE"]); -const PROXY_ERRORS = new Set(["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]); - -function sleep(seconds) { - return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); -} - -function validateConfig() { - if (!API_KEY || API_KEY === "YOUR_API_KEY") { - console.log("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - console.log(" Copy .env.example to .env and add your real API key."); - process.exit(1); - } - if (!CAPTCHA_SITEKEY || CAPTCHA_SITEKEY === "YOUR_SITE_KEY") { - console.log("[!] ERROR: CAPTCHA_SITEKEY is not set."); - console.log(" Add the hCaptcha sitekey from your target page to .env"); - process.exit(1); - } - if (!CAPTCHA_PAGEURL || CAPTCHA_PAGEURL === "https://example.com/login") { - console.log("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - console.log(" Make sure it points to the actual target page."); - } -} - -async function submitTask() { - console.log("[*] Submitting hCaptcha task..."); - - const params = { - key: API_KEY, - method: "hcaptcha", - sitekey: CAPTCHA_SITEKEY, - pageurl: CAPTCHA_PAGEURL, - json: "1", - }; - - let resp; - try { - resp = await axios.get(SUBMIT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during submission: ${err.message}`); - process.exit(1); - } - - const data = resp.data; - if (data.status !== 1) { - const error = data.request || "UNKNOWN_ERROR"; - if (AUTH_ERRORS.has(error)) { - console.log(`[!] Authentication error: ${error}`); - console.log(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.has(error)) { - console.log(`[!] Balance error: ${error}`); - console.log(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.has(error)) { - console.log(`[!] Input error: ${error}`); - console.log(" Verify your sitekey and page URL are correct."); - } else if (PROXY_ERRORS.has(error)) { - console.log(`[!] Proxy error: ${error}`); - console.log(" Check your proxy configuration or try a different proxy."); - } else { - console.log(`[!] Submission failed: ${error}`); - } - process.exit(1); - } - - const taskId = data.request; - console.log(`[+] Task submitted. ID: ${taskId}`); - return taskId; -} - -async function pollResult(taskId) { - console.log("[*] Waiting 15s before first poll..."); - await sleep(15); - - const params = { key: API_KEY, action: "get", id: taskId, json: "1" }; - let elapsed = 15; - let attempt = 0; - let backoff = POLL_INTERVAL; - - while (elapsed < MAX_TIMEOUT) { - attempt++; - console.log(`[*] Polling for result (attempt ${attempt})...`); - - let resp; - try { - resp = await axios.get(RESULT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during polling: ${err.message}`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - const data = resp.data; - - if (data.status === 1) { - return data.request; - } - - const error = data.request || ""; - if (error === "CAPCHA_NOT_READY") { - console.log(`[*] Not ready yet, waiting ${POLL_INTERVAL}s...`); - await sleep(POLL_INTERVAL); - elapsed += POLL_INTERVAL; - backoff = POLL_INTERVAL; - continue; - } - - if (TRANSIENT_ERRORS.has(error)) { - console.log(`[!] Transient error: ${error}, retrying in ${backoff}s...`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.has(error)) { - console.log(`[!] Solve error: ${error}`); - console.log(" The CAPTCHA could not be solved. Verify parameters and retry."); - process.exit(1); - } - - console.log(`[!] Unexpected error: ${error}`); - process.exit(1); - } - - console.log(`[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds.`); - process.exit(1); -} - -async function main() { - validateConfig(); - const taskId = await submitTask(); - const token = await pollResult(taskId); - console.log(`[+] Solved! Token: ${token.substring(0, 50)}...`); - console.log(`[+] Full token length: ${token.length} characters`); - console.log(); - console.log("Next step: inject this token into the target page's"); - console.log("h-captcha-response hidden field and submit the form."); -} - -main(); diff --git a/articles/how-to-solve-hcaptcha-using-api/php/composer.json b/articles/how-to-solve-hcaptcha-using-api/php/composer.json deleted file mode 100644 index b5b328f..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/php/composer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "captchaai/hcaptcha-example", - "description": "Solve hCaptcha using CaptchaAI API", - "require": { - "vlucas/phpdotenv": "^5.5" - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/php/solve.php b/articles/how-to-solve-hcaptcha-using-api/php/solve.php deleted file mode 100644 index 671c633..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/php/solve.php +++ /dev/null @@ -1,157 +0,0 @@ -load(); - -define('SUBMIT_URL', 'https://ocr.captchaai.com/in.php'); -define('RESULT_URL', 'https://ocr.captchaai.com/res.php'); - -$apiKey = $_ENV['CAPTCHAAI_API_KEY'] ?? ''; -$sitekey = $_ENV['CAPTCHA_SITEKEY'] ?? ''; -$pageurl = $_ENV['CAPTCHA_PAGEURL'] ?? ''; -$pollInterval = (int)($_ENV['POLL_INTERVAL'] ?? 5); -$maxTimeout = (int)($_ENV['MAX_TIMEOUT'] ?? 120); - -$authErrors = ['ERROR_WRONG_USER_KEY', 'ERROR_KEY_DOES_NOT_EXIST', 'IP_BANNED']; -$balanceErrors = ['ERROR_ZERO_BALANCE']; -$inputErrors = ['ERROR_PAGEURL', 'ERROR_WRONG_GOOGLEKEY', 'ERROR_BAD_PARAMETERS', 'ERROR_BAD_TOKEN_OR_PAGEURL']; -$transientErrors = ['ERROR_SERVER_ERROR', 'ERROR_INTERNAL_SERVER_ERROR']; -$solveErrors = ['ERROR_CAPTCHA_UNSOLVABLE']; -$proxyErrors = ['ERROR_BAD_PROXY', 'ERROR_PROXY_CONNECTION_FAILED']; - -// --- Validate configuration --- -if (empty($apiKey) || $apiKey === 'YOUR_API_KEY') { - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set.\n"; - echo " Copy .env.example to .env and add your real API key.\n"; - exit(1); -} -if (empty($sitekey) || $sitekey === 'YOUR_SITE_KEY') { - echo "[!] ERROR: CAPTCHA_SITEKEY is not set.\n"; - echo " Add the hCaptcha sitekey from your target page to .env\n"; - exit(1); -} -if (empty($pageurl) || $pageurl === 'https://example.com/login') { - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.\n"; - echo " Make sure it points to the actual target page.\n"; -} - -// --- Submit task --- -echo "[*] Submitting hCaptcha task...\n"; -$submitParams = http_build_query([ - 'key' => $apiKey, - 'method' => 'hcaptcha', - 'sitekey' => $sitekey, - 'pageurl' => $pageurl, - 'json' => '1', -]); - -$ctx = stream_context_create(['http' => ['timeout' => 30]]); -$submitResponse = @file_get_contents(SUBMIT_URL . '?' . $submitParams, false, $ctx); -if ($submitResponse === false) { - echo "[!] Network error during submission.\n"; - exit(1); -} - -$submitData = json_decode($submitResponse, true); -if (($submitData['status'] ?? 0) !== 1) { - $error = $submitData['request'] ?? 'UNKNOWN_ERROR'; - if (in_array($error, $authErrors)) { - echo "[!] Authentication error: $error\n"; - echo " Check your API key at https://captchaai.com/dashboard\n"; - } elseif (in_array($error, $balanceErrors)) { - echo "[!] Balance error: $error\n"; - echo " Top up your account at https://captchaai.com\n"; - } elseif (in_array($error, $inputErrors)) { - echo "[!] Input error: $error\n"; - echo " Verify your sitekey and page URL are correct.\n"; - } elseif (in_array($error, $proxyErrors)) { - echo "[!] Proxy error: $error\n"; - echo " Check your proxy configuration or try a different proxy.\n"; - } else { - echo "[!] Submission failed: $error\n"; - } - exit(1); -} - -$taskId = $submitData['request']; -echo "[+] Task submitted. ID: $taskId\n"; - -// --- Poll for result --- -echo "[*] Waiting 15s before first poll...\n"; -sleep(15); - -$elapsed = 15; -$attempt = 0; -$backoff = $pollInterval; - -while ($elapsed < $maxTimeout) { - $attempt++; - echo "[*] Polling for result (attempt $attempt)...\n"; - - $resultParams = http_build_query([ - 'key' => $apiKey, - 'action' => 'get', - 'id' => $taskId, - 'json' => '1', - ]); - - $resultResponse = @file_get_contents(RESULT_URL . '?' . $resultParams, false, $ctx); - if ($resultResponse === false) { - echo "[!] Network error during polling.\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - $resultData = json_decode($resultResponse, true); - - if (($resultData['status'] ?? 0) === 1) { - $token = $resultData['request']; - echo "[+] Solved! Token: " . substr($token, 0, 50) . "...\n"; - echo "[+] Full token length: " . strlen($token) . " characters\n"; - echo "\n"; - echo "Next step: inject this token into the target page's\n"; - echo "h-captcha-response hidden field and submit the form.\n"; - exit(0); - } - - $error = $resultData['request'] ?? ''; - if ($error === 'CAPCHA_NOT_READY') { - echo "[*] Not ready yet, waiting {$pollInterval}s...\n"; - sleep($pollInterval); - $elapsed += $pollInterval; - $backoff = $pollInterval; - continue; - } - - if (in_array($error, $transientErrors)) { - echo "[!] Transient error: $error, retrying in {$backoff}s...\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - if (in_array($error, $solveErrors)) { - echo "[!] Solve error: $error\n"; - echo " The CAPTCHA could not be solved. Verify parameters and retry.\n"; - exit(1); - } - - echo "[!] Unexpected error: $error\n"; - exit(1); -} - -echo "[!] Timeout: no solution received within {$maxTimeout} seconds.\n"; -exit(1); diff --git a/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt b/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt deleted file mode 100644 index f49b6b8..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests>=2.28.0 -python-dotenv>=1.0.0 diff --git a/articles/how-to-solve-hcaptcha-using-api/python/solve.py b/articles/how-to-solve-hcaptcha-using-api/python/solve.py deleted file mode 100644 index 62a7f8b..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/python/solve.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Solve hCaptcha using the CaptchaAI API. - -Usage: - pip install -r requirements.txt - cp ../.env.example ../.env # then edit with your credentials - python solve.py -""" - -import os -import sys -import time - -import requests -from dotenv import load_dotenv - -# Load environment variables from the parent .env file -load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env")) - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -API_KEY = os.getenv("CAPTCHAAI_API_KEY", "") -CAPTCHA_SITEKEY = os.getenv("CAPTCHA_SITEKEY", "") -CAPTCHA_PAGEURL = os.getenv("CAPTCHA_PAGEURL", "") -POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "5")) -MAX_TIMEOUT = int(os.getenv("MAX_TIMEOUT", "120")) - -# --- Error categories --- -AUTH_ERRORS = {"ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"} -BALANCE_ERRORS = {"ERROR_ZERO_BALANCE"} -INPUT_ERRORS = {"ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"} -TRANSIENT_ERRORS = {"ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"} -SOLVE_ERRORS = {"ERROR_CAPTCHA_UNSOLVABLE"} -PROXY_ERRORS = {"ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"} - - -def validate_config() -> None: - """Check that required environment variables are set.""" - if not API_KEY or API_KEY == "YOUR_API_KEY": - print("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - print(" Copy .env.example to .env and add your real API key.") - sys.exit(1) - if not CAPTCHA_SITEKEY or CAPTCHA_SITEKEY == "YOUR_SITE_KEY": - print("[!] ERROR: CAPTCHA_SITEKEY is not set.") - print(" Add the hCaptcha sitekey from your target page to .env") - sys.exit(1) - if not CAPTCHA_PAGEURL or CAPTCHA_PAGEURL == "https://example.com/login": - print("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - print(" Make sure it points to the actual target page.") - - -def submit_task() -> str: - """Submit the CAPTCHA task and return the task ID.""" - print("[*] Submitting hCaptcha task...") - payload = { - "key": API_KEY, - "method": "hcaptcha", - "sitekey": CAPTCHA_SITEKEY, - "pageurl": CAPTCHA_PAGEURL, - "json": "1", - } - - try: - resp = requests.get(SUBMIT_URL, params=payload, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during submission: {exc}") - sys.exit(1) - - data = resp.json() - - if data.get("status") != 1: - error = data.get("request", "UNKNOWN_ERROR") - if error in AUTH_ERRORS: - print(f"[!] Authentication error: {error}") - print(" Check your API key at https://captchaai.com/dashboard") - elif error in BALANCE_ERRORS: - print(f"[!] Balance error: {error}") - print(" Top up your account at https://captchaai.com") - elif error in INPUT_ERRORS: - print(f"[!] Input error: {error}") - print(" Verify your sitekey and page URL are correct.") - elif error in PROXY_ERRORS: - print(f"[!] Proxy error: {error}") - print(" Check your proxy configuration or try a different proxy.") - else: - print(f"[!] Submission failed: {error}") - sys.exit(1) - - task_id = data["request"] - print(f"[+] Task submitted. ID: {task_id}") - return task_id - - -def poll_result(task_id: str) -> str: - """Poll for the CAPTCHA solution with timeout and retry logic.""" - print("[*] Waiting 15s before first poll...") - time.sleep(15) - - params = { - "key": API_KEY, - "action": "get", - "id": task_id, - "json": "1", - } - - elapsed = 15 - attempt = 0 - backoff = POLL_INTERVAL - - while elapsed < MAX_TIMEOUT: - attempt += 1 - print(f"[*] Polling for result (attempt {attempt})...") - - try: - resp = requests.get(RESULT_URL, params=params, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during polling: {exc}") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - data = resp.json() - - if data.get("status") == 1: - return data["request"] - - error = data.get("request", "") - if error == "CAPCHA_NOT_READY": - print(f"[*] Not ready yet, waiting {POLL_INTERVAL}s...") - time.sleep(POLL_INTERVAL) - elapsed += POLL_INTERVAL - backoff = POLL_INTERVAL - continue - - if error in TRANSIENT_ERRORS: - print(f"[!] Transient error: {error}, retrying in {backoff}s...") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - if error in SOLVE_ERRORS: - print(f"[!] Solve error: {error}") - print(" The CAPTCHA could not be solved. Verify parameters and retry.") - sys.exit(1) - - print(f"[!] Unexpected error: {error}") - sys.exit(1) - - print(f"[!] Timeout: no solution received within {MAX_TIMEOUT} seconds.") - sys.exit(1) - - -def main() -> None: - validate_config() - task_id = submit_task() - token = poll_result(task_id) - print(f"[+] Solved! Token: {token[:50]}...") - print(f"[+] Full token length: {len(token)} characters") - print() - print("Next step: inject this token into the target page's") - print("h-captcha-response hidden field and submit the form.") - - -if __name__ == "__main__": - main() diff --git a/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile b/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile deleted file mode 100644 index 05a677e..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source "https://rubygems.org" -# No external gems needed — uses Ruby stdlib (net/http, json, uri) diff --git a/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb b/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb deleted file mode 100644 index 577b959..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb +++ /dev/null @@ -1,184 +0,0 @@ -# Solve hCaptcha using the CaptchaAI API. -# -# Usage: -# ruby solve.rb - -require "net/http" -require "json" -require "uri" - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -AUTH_ERRORS = %w[ERROR_WRONG_USER_KEY ERROR_KEY_DOES_NOT_EXIST IP_BANNED].freeze -BALANCE_ERRORS = %w[ERROR_ZERO_BALANCE].freeze -INPUT_ERRORS = %w[ERROR_PAGEURL ERROR_WRONG_GOOGLEKEY ERROR_BAD_PARAMETERS ERROR_BAD_TOKEN_OR_PAGEURL].freeze -TRANSIENT_ERRORS = %w[ERROR_SERVER_ERROR ERROR_INTERNAL_SERVER_ERROR].freeze -SOLVE_ERRORS = %w[ERROR_CAPTCHA_UNSOLVABLE].freeze -PROXY_ERRORS = %w[ERROR_BAD_PROXY ERROR_PROXY_CONNECTION_FAILED].freeze - -def load_env(path) - env = {} - return env unless File.exist?(path) - File.readlines(path).each do |line| - line = line.strip - next if line.empty? || line.start_with?("#") - key, value = line.split("=", 2) - env[key.strip] = value&.strip || "" - end - env -end - -def get_env(env, key, fallback = "") - v = env[key] - return v if v && !v.empty? - v = ENV[key] - return v if v && !v.empty? - fallback -end - -env = load_env(File.join(__dir__, "..", ".env")) -api_key = get_env(env, "CAPTCHAAI_API_KEY") -sitekey = get_env(env, "CAPTCHA_SITEKEY") -pageurl = get_env(env, "CAPTCHA_PAGEURL") -poll_interval = get_env(env, "POLL_INTERVAL", "5").to_i -max_timeout = get_env(env, "MAX_TIMEOUT", "120").to_i - -# Validate -if api_key.empty? || api_key == "YOUR_API_KEY" - puts "[!] ERROR: CAPTCHAAI_API_KEY is not set." - puts " Copy .env.example to .env and add your real API key." - exit 1 -end -if sitekey.empty? || sitekey == "YOUR_SITE_KEY" - puts "[!] ERROR: CAPTCHA_SITEKEY is not set." - puts " Add the hCaptcha sitekey from your target page to .env" - exit 1 -end -if pageurl.empty? || pageurl == "https://example.com/login" - puts "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - puts " Make sure it points to the actual target page." -end - -def handle_error(error) - if AUTH_ERRORS.include?(error) - puts "[!] Authentication error: #{error}" - puts " Check your API key at https://captchaai.com/dashboard" - elsif BALANCE_ERRORS.include?(error) - puts "[!] Balance error: #{error}" - puts " Top up your account at https://captchaai.com" - elsif INPUT_ERRORS.include?(error) - puts "[!] Input error: #{error}" - puts " Verify your sitekey and page URL are correct." - elsif PROXY_ERRORS.include?(error) - puts "[!] Proxy error: #{error}" - puts " Check your proxy configuration or try a different proxy." - else - puts "[!] Submission failed: #{error}" - end -end - -def http_get(url_str) - uri = URI(url_str) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.open_timeout = 30 - http.read_timeout = 30 - response = http.get("#{uri.path}?#{uri.query}") - JSON.parse(response.body) -end - -# Submit task -puts "[*] Submitting hCaptcha task..." -params = URI.encode_www_form( - key: api_key, - method: "hcaptcha", - sitekey: sitekey, - pageurl: pageurl, - json: "1" -) - -begin - submit_data = http_get("#{SUBMIT_URL}?#{params}") -rescue StandardError => e - puts "[!] Network error during submission: #{e.message}" - exit 1 -end - -unless submit_data["status"] == 1 - handle_error(submit_data["request"] || "UNKNOWN_ERROR") - exit 1 -end - -task_id = submit_data["request"] -puts "[+] Task submitted. ID: #{task_id}" - -# Poll for result -puts "[*] Waiting 15s before first poll..." -sleep 15 - -elapsed = 15 -attempt = 0 -backoff = poll_interval - -while elapsed < max_timeout - attempt += 1 - puts "[*] Polling for result (attempt #{attempt})..." - - poll_params = URI.encode_www_form( - key: api_key, - action: "get", - id: task_id, - json: "1" - ) - - begin - result_data = http_get("#{RESULT_URL}?#{poll_params}") - rescue StandardError => e - puts "[!] Network error during polling: #{e.message}" - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if result_data["status"] == 1 - token = result_data["request"] - display = token.length > 50 ? token[0, 50] : token - puts "[+] Solved! Token: #{display}..." - puts "[+] Full token length: #{token.length} characters" - puts - puts "Next step: inject this token into the target page's" - puts "h-captcha-response hidden field and submit the form." - exit 0 - end - - error = result_data["request"] || "" - if error == "CAPCHA_NOT_READY" - puts "[*] Not ready yet, waiting #{poll_interval}s..." - sleep poll_interval - elapsed += poll_interval - backoff = poll_interval - next - end - - if TRANSIENT_ERRORS.include?(error) - puts "[!] Transient error: #{error}, retrying in #{backoff}s..." - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if SOLVE_ERRORS.include?(error) - puts "[!] Solve error: #{error}" - puts " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - end - - puts "[!] Unexpected error: #{error}" - exit 1 -end - -puts "[!] Timeout: no solution received within #{max_timeout} seconds." -exit 1 diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock b/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock deleted file mode 100644 index 8b07fcd..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock +++ /dev/null @@ -1,675 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "captchaai-hcaptcha-example" -version = "1.0.0" -dependencies = [ - "serde_json", - "ureq", - "urlencoding", -] - -[[package]] -name = "cc" -version = "1.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "libc" -version = "0.2.185" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "untrusted", - "windows-sys", -] - -[[package]] -name = "rustls" -version = "0.23.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots 0.26.11", -] - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.7", -] - -[[package]] -name = "webpki-roots" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml b/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml deleted file mode 100644 index 5d52eef..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "captchaai-hcaptcha-example" -version = "1.0.0" -edition = "2021" - -[dependencies] -ureq = "2" -serde_json = "1" -urlencoding = "2" diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs b/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs deleted file mode 100644 index e0778e5..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs +++ /dev/null @@ -1,219 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// cargo run - -use std::collections::HashMap; -use std::fs; -use std::path::Path; -use std::thread; -use std::time::Duration; - -const SUBMIT_URL: &str = "https://ocr.captchaai.com/in.php"; -const RESULT_URL: &str = "https://ocr.captchaai.com/res.php"; - -fn load_env(path: &str) -> HashMap { - let mut env = HashMap::new(); - if let Ok(content) = fs::read_to_string(path) { - for line in content.lines() { - let trimmed = line.trim(); - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - if let Some((key, value)) = trimmed.split_once('=') { - env.insert(key.trim().to_string(), value.trim().to_string()); - } - } - } - env -} - -fn get_env(env: &HashMap, key: &str, fallback: &str) -> String { - if let Some(v) = env.get(key) { - if !v.is_empty() { - return v.clone(); - } - } - if let Ok(v) = std::env::var(key) { - if !v.is_empty() { - return v; - } - } - fallback.to_string() -} - -fn json_str(json: &str, key: &str) -> String { - let pattern = format!("\"{}\":\"", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - if let Some(end) = json[start..].find('"') { - return json[start..start + end].to_string(); - } - } - String::new() -} - -fn json_int(json: &str, key: &str) -> i32 { - let pattern = format!("\"{}\":", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - let num_str: String = json[start..] - .chars() - .take_while(|c| c.is_ascii_digit() || *c == '-') - .collect(); - return num_str.parse().unwrap_or(0); - } - 0 -} - -fn handle_error(error: &str) { - let auth = ["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]; - let balance = ["ERROR_ZERO_BALANCE"]; - let input = ["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]; - let proxy = ["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]; - - if auth.contains(&error) { - println!("[!] Authentication error: {}", error); - println!(" Check your API key at https://captchaai.com/dashboard"); - } else if balance.contains(&error) { - println!("[!] Balance error: {}", error); - println!(" Top up your account at https://captchaai.com"); - } else if input.contains(&error) { - println!("[!] Input error: {}", error); - println!(" Verify your sitekey and page URL are correct."); - } else if proxy.contains(&error) { - println!("[!] Proxy error: {}", error); - println!(" Check your proxy configuration or try a different proxy."); - } else { - println!("[!] Submission failed: {}", error); - } -} - -fn main() { - let env = load_env("../.env"); - let api_key = get_env(&env, "CAPTCHAAI_API_KEY", ""); - let sitekey = get_env(&env, "CAPTCHA_SITEKEY", ""); - let pageurl = get_env(&env, "CAPTCHA_PAGEURL", ""); - let poll_interval: u64 = get_env(&env, "POLL_INTERVAL", "5").parse().unwrap_or(5); - let max_timeout: u64 = get_env(&env, "MAX_TIMEOUT", "120").parse().unwrap_or(120); - - // Validate - if api_key.is_empty() || api_key == "YOUR_API_KEY" { - println!("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - println!(" Copy .env.example to .env and add your real API key."); - std::process::exit(1); - } - if sitekey.is_empty() || sitekey == "YOUR_SITE_KEY" { - println!("[!] ERROR: CAPTCHA_SITEKEY is not set."); - println!(" Add the hCaptcha sitekey from your target page to .env"); - std::process::exit(1); - } - if pageurl.is_empty() || pageurl == "https://example.com/login" { - println!("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - println!(" Make sure it points to the actual target page."); - } - - // Submit task - println!("[*] Submitting hCaptcha task..."); - let submit_url = format!( - "{}?key={}&method=hcaptcha&sitekey={}&pageurl={}&json=1", - SUBMIT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&sitekey), - urlencoding::encode(&pageurl) - ); - - let submit_resp = match ureq::get(&submit_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during submission: {}", e); - std::process::exit(1); - } - }; - - let submit_status = json_int(&submit_resp, "status"); - let submit_request = json_str(&submit_resp, "request"); - - if submit_status != 1 { - handle_error(&submit_request); - std::process::exit(1); - } - - let task_id = submit_request; - println!("[+] Task submitted. ID: {}", task_id); - - // Poll for result - println!("[*] Waiting 15s before first poll..."); - thread::sleep(Duration::from_secs(15)); - - let mut elapsed: u64 = 15; - let mut attempt = 0; - let mut backoff = poll_interval; - - let transient = ["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]; - let solve = ["ERROR_CAPTCHA_UNSOLVABLE"]; - - while elapsed < max_timeout { - attempt += 1; - println!("[*] Polling for result (attempt {})...", attempt); - - let poll_url = format!( - "{}?key={}&action=get&id={}&json=1", - RESULT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&task_id) - ); - - let result_resp = match ureq::get(&poll_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during polling: {}", e); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - }; - - let status = json_int(&result_resp, "status"); - let request = json_str(&result_resp, "request"); - - if status == 1 { - let display = if request.len() > 50 { &request[..50] } else { &request }; - println!("[+] Solved! Token: {}...", display); - println!("[+] Full token length: {} characters", request.len()); - println!(); - println!("Next step: inject this token into the target page's"); - println!("h-captcha-response hidden field and submit the form."); - return; - } - - if request == "CAPCHA_NOT_READY" { - println!("[*] Not ready yet, waiting {}s...", poll_interval); - thread::sleep(Duration::from_secs(poll_interval)); - elapsed += poll_interval; - backoff = poll_interval; - continue; - } - - if transient.contains(&request.as_str()) { - println!("[!] Transient error: {}, retrying in {}s...", request, backoff); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - - if solve.contains(&request.as_str()) { - println!("[!] Solve error: {}", request); - println!(" The CAPTCHA could not be solved. Verify parameters and retry."); - std::process::exit(1); - } - - println!("[!] Unexpected error: {}", request); - std::process::exit(1); - } - - println!("[!] Timeout: no solution received within {} seconds.", max_timeout); - std::process::exit(1); -}