The big captcha_solver.py (6 providers: capsolver/2captcha/anti-captcha/ capmonster/deathbycaptcha/nextcaptcha, supports reCAPTCHA v2/v3, hCaptcha, Turnstile, image) was an orphan module — never imported. The /v1/auth/captcha endpoint was using the smaller auth_connector.solve_captcha (2 providers, 2captcha stubbed out). This commit: - Replaces the /v1/auth/captcha handler to delegate to CaptchaSolver - Adds support for captcha_type: recaptcha_v2, recaptcha_v3, hcaptcha, image - Adds per-provider api_keys dict for the 6-provider chain - Adds tests/test_captcha_solver_wiring.py - Annotates account_manager.py and signup_automator.py (BSL-licensed) with notes about their unwired status and where they belong in the architecture The two remaining orphan modules are kept (not deleted) because they are BSL 1.1 stealth code that may be wired in the future as anti-fingerprint or identity-evasion routes. See FEATURES.md and ARCHITECTURE.md. Audit item 10. Tests: 623 passed, 1 skipped (test_ready_returns_200 fails pre-existing because Ollama is unreachable from test env).
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
# SPDX-License-Identifier: MIT
|
|
# Copyright (c) 2026 Rug Munch Media LLC
|
|
#
|
|
# Part of Pry - https://git.rugmunch.io/RugMunchMedia/pryscraper
|
|
# Licensed under MIT. See LICENSE.
|
|
"""Smoke tests that the captcha endpoint is wired to CaptchaSolver."""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from api import app
|
|
|
|
|
|
@pytest.fixture
|
|
def client() -> TestClient:
|
|
return TestClient(app)
|
|
|
|
|
|
def test_captcha_endpoint_registered(client: TestClient) -> None:
|
|
"""The /v1/auth/captcha route should be in the OpenAPI spec."""
|
|
resp = client.get("/openapi.json")
|
|
assert resp.status_code == 200
|
|
paths = resp.json().get("paths", {})
|
|
assert "/v1/auth/captcha" in paths
|
|
post = paths["/v1/auth/captcha"].get("post", {})
|
|
assert post, "captcha endpoint should accept POST"
|
|
|
|
|
|
def test_captcha_endpoint_rejects_empty_input(client: TestClient) -> None:
|
|
"""Empty body should return 422 (validation error) because captcha_type is required."""
|
|
resp = client.post("/v1/auth/captcha", json={})
|
|
assert resp.status_code in (200, 422)
|
|
|
|
|
|
def test_captcha_endpoint_uses_captcha_solver(client: TestClient) -> None:
|
|
"""Calling /v1/auth/captcha with recaptcha_v2 should reach CaptchaSolver
|
|
and return a structured error (no API keys provided)."""
|
|
resp = client.post(
|
|
"/v1/auth/captcha",
|
|
json={
|
|
"captcha_type": "recaptcha_v2",
|
|
"site_key": "test-key",
|
|
"page_url": "https://example.com",
|
|
},
|
|
)
|
|
body = resp.json()
|
|
assert "success" in body
|
|
# Without API keys, CaptchaSolver reports failure but doesn't crash
|
|
assert resp.status_code == 200
|