security: fix #1 — wire SSRF hook into detect_site_type client

detect_site_type constructs a fresh BooruClient._shared_client
directly (bypassing the BooruClient.client property) for the
/posts.json, /index.php, and /post.json probes. The hooks set
here are the ones installed on that initial construction — if
detection runs before any BooruClient instance's .client is
accessed, the shared singleton must still have SSRF validation
and connection logging.

This additionally closes finding #16 for the detect client — site
detection requests now appear in the connection log instead of
being invisible.

behavior change from v0.2.5: Test Connection from the site dialog
now rejects private-IP targets. Adding a local/RFC1918 booru via
the "auto-detect type" dialog will fail with "blocked request
target ..." instead of probing it. Explicit api_type selection
still goes through the BooruClient.client path, which is also
now protected.

Audit-Ref: SECURITY_AUDIT.md finding #1
Also-Closes: SECURITY_AUDIT.md finding #16 (detect half)
Severity: High
This commit is contained in:
pax 2026-04-11 16:11:37 -05:00
parent ef95509551
commit c735db0c68

View File

@ -7,6 +7,7 @@ import logging
import httpx
from ..config import USER_AGENT
from ._safety import validate_public_request
from .danbooru import DanbooruClient
from .gelbooru import GelbooruClient
from .moebooru import MoebooruClient
@ -28,12 +29,20 @@ async def detect_site_type(
url = url.rstrip("/")
from .base import BooruClient as _BC
# Reuse shared client for site detection
# Reuse shared client for site detection. event_hooks mirrors
# BooruClient.client so detection requests get the same SSRF
# validation and connection logging as regular API calls.
if _BC._shared_client is None or _BC._shared_client.is_closed:
_BC._shared_client = httpx.AsyncClient(
headers={"User-Agent": USER_AGENT},
follow_redirects=True,
timeout=20.0,
event_hooks={
"request": [
validate_public_request,
_BC._log_request,
],
},
limits=httpx.Limits(max_connections=10, max_keepalive_connections=5),
)
client = _BC._shared_client