## Problem CSES `_web_login` used bare dict indexing on the API response, raising an opaque `KeyError` on missing fields. `_check_token` swallowed all exceptions as `False`, conflating transient network errors with invalid tokens. CF persisted cookies unconditionally and silently swallowed `_solve_turnstile` failures in `submit_action`. ## Solution CSES API fields now use `.get()` with a descriptive `RuntimeError` on absence. `_check_token` re-raises `httpx` network/timeout exceptions so callers see real failures. CF cookie writes are guarded by an `X-User-Handle` check (the CF auth cookie). `_solve_turnstile` errors propagate to the outer error handler instead of being silenced.
This commit is contained in:
parent
6c036a7b2e
commit
b959f29bd4
2 changed files with 12 additions and 10 deletions
|
|
@ -401,7 +401,8 @@ def _login_headless_cf(credentials: dict[str, str]) -> LoginResult:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
browser_cookies = session.context.cookies()
|
browser_cookies = session.context.cookies()
|
||||||
cookie_cache.write_text(json.dumps(browser_cookies))
|
if any(c.get("name") == "X-User-Handle" for c in browser_cookies):
|
||||||
|
cookie_cache.write_text(json.dumps(browser_cookies))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -478,10 +479,7 @@ def _submit_headless(
|
||||||
if "/enter" in page.url or "/login" in page.url:
|
if "/enter" in page.url or "/login" in page.url:
|
||||||
needs_relogin = True
|
needs_relogin = True
|
||||||
return
|
return
|
||||||
try:
|
_solve_turnstile(page)
|
||||||
_solve_turnstile(page)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
try:
|
try:
|
||||||
page.select_option(
|
page.select_option(
|
||||||
'select[name="submittedProblemIndex"]',
|
'select[name="submittedProblemIndex"]',
|
||||||
|
|
@ -550,7 +548,7 @@ def _submit_headless(
|
||||||
|
|
||||||
try:
|
try:
|
||||||
browser_cookies = session.context.cookies()
|
browser_cookies = session.context.cookies()
|
||||||
if browser_cookies:
|
if any(c.get("name") == "X-User-Handle" for c in browser_cookies):
|
||||||
cookie_cache.write_text(json.dumps(browser_cookies))
|
cookie_cache.write_text(json.dumps(browser_cookies))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,12 @@ class CSESScraper(BaseScraper):
|
||||||
f"{API_URL}/login", headers=HEADERS, timeout=HTTP_TIMEOUT
|
f"{API_URL}/login", headers=HEADERS, timeout=HTTP_TIMEOUT
|
||||||
)
|
)
|
||||||
api_data = api_resp.json()
|
api_data = api_resp.json()
|
||||||
token: str = api_data["X-Auth-Token"]
|
token: str | None = api_data.get("X-Auth-Token")
|
||||||
auth_url: str = api_data["authentication_url"]
|
auth_url: str | None = api_data.get("authentication_url")
|
||||||
|
if not token:
|
||||||
|
raise RuntimeError("CSES API login response missing 'X-Auth-Token'")
|
||||||
|
if not auth_url:
|
||||||
|
raise RuntimeError("CSES API login response missing 'authentication_url'")
|
||||||
|
|
||||||
auth_page = await client.get(auth_url, headers=HEADERS, timeout=HTTP_TIMEOUT)
|
auth_page = await client.get(auth_url, headers=HEADERS, timeout=HTTP_TIMEOUT)
|
||||||
auth_csrf = re.search(r'name="csrf_token" value="([^"]+)"', auth_page.text)
|
auth_csrf = re.search(r'name="csrf_token" value="([^"]+)"', auth_page.text)
|
||||||
|
|
@ -388,8 +392,8 @@ class CSESScraper(BaseScraper):
|
||||||
timeout=HTTP_TIMEOUT,
|
timeout=HTTP_TIMEOUT,
|
||||||
)
|
)
|
||||||
return r.status_code == 200
|
return r.status_code == 200
|
||||||
except Exception:
|
except (httpx.ConnectError, httpx.TimeoutException, httpx.NetworkError):
|
||||||
return False
|
raise
|
||||||
|
|
||||||
async def submit(
|
async def submit(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue