diff --git a/shelfmark/bypass/cookie_store.py b/shelfmark/bypass/cookie_store.py index 2b4e1d3b..70a236b2 100644 --- a/shelfmark/bypass/cookie_store.py +++ b/shelfmark/bypass/cookie_store.py @@ -38,6 +38,10 @@ DDG_COOKIE_NAMES = { "ddg_last_challenge", } +# Anna's Archive's own pass for its ?check=1 hop. Without it the hop 302s back +# forever, however good the __ddg* clearance is. +AA_COOKIE_NAMES = {"aa_ddg_check"} + # DDoS-Guard cookies that describe *one* check rather than granting clearance, and so # must never be replayed on a later request. Observed live on Anna's Archive: # @@ -88,7 +92,8 @@ def _should_extract_cookie(name: str, *, extract_all: bool) -> bool: return True is_cf = name in CF_COOKIE_NAMES or name.startswith("cf_") is_ddg = name in DDG_COOKIE_NAMES or name.startswith("__ddg") - return is_cf or is_ddg + is_aa = name in AA_COOKIE_NAMES + return is_cf or is_ddg or is_aa def _cookie_field(cookie: Any, name: str) -> Any: diff --git a/tests/bypass/test_ddg_cookie_reuse.py b/tests/bypass/test_ddg_cookie_reuse.py index 3bf64315..770efef5 100644 --- a/tests/bypass/test_ddg_cookie_reuse.py +++ b/tests/bypass/test_ddg_cookie_reuse.py @@ -1,11 +1,12 @@ """DDoS-Guard cookie reuse between requests. -Anna's Archive issues nine cookies after a solve, and they are not equivalent: +Anna's Archive issues ten cookies after a solve, and they are not equivalent: __ddg1_/__ddg2_/__ddgid_ ~1 year clearance __ddgmark_ ~1 day __ddg5_ session __ddg8_/__ddg9_/__ddg10_ ~40 min one check: token, CLIENT IP, TIMESTAMP + aa_ddg_check ~90 days Anna's Archive's own pass for its ?check=1 hop Replaying the last three is what produces the ?check=1 redirect loop. They describe a single check, so once the timestamp ages out - or the egress IP changes, routine @@ -97,6 +98,15 @@ def test_per_check_cookies_are_not_stored(): assert ephemeral not in stored +def test_aa_check_cookie_is_stored(): + """Without aa_ddg_check the ?check=1 hop loops, whatever __ddg* is replayed.""" + _store([_Cookie("__ddg1_", "a"), _Cookie("__ddg5_", "b"), _Cookie("aa_ddg_check", "ok")]) + + stored = ib.get_cf_cookies_for_domain("annas-archive.gl") + + assert stored == {"__ddg1_": "a", "__ddg5_": "b", "aa_ddg_check": "ok"} + + def test_clearance_cookies_survive(): _store([_Cookie("__ddg1_", "a"), _Cookie("__ddg2_", "b"), _Cookie("__ddgid_", "c")])