1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Demonstrates the P5 Cloudflare Turnstile bypass driver.
//!
//! Sequence:
//! 1. Launch a headless browser and navigate to a Cloudflare-protected
//! URL. Set this to whatever endpoint you actually want to clear.
//! 2. Call [`Tab::cloudflare`] to construct a [`CloudflareBypass`] bound
//! to the tab's session.
//! 3. Call [`CloudflareBypass::wait_for_clearance`] with a 30s budget.
//! The driver runs a single CDP poll loop that, per tick, looks for
//! the `cf-turnstile-response` token, the Turnstile challenge
//! iframe's bounding box (shadow-DOM aware), and any challenge marker
//! on the page. When the interactive iframe is present and we have
//! not yet clicked it, the driver dispatches a single raw left-click
//! at the canonical (15% x, 50% y) offset (Turnstile checkbox).
//! Resolves the first tick a token is observed or the iframe is gone
//! after a click.
//! 4. Print the [`ClearanceOutcome`] enum variant + the page title.
//!
//! Outcomes:
//! - `TokenAcquired(_)` — Turnstile yielded a `cf-turnstile-response`
//! token, either after clicking the checkbox or directly (invisible
//! Turnstile, where the iframe never mounts).
//! - `ChallengeGone` — the interactive iframe was clicked and the
//! challenge container then disappeared without a token (e.g.
//! clearance-cookie shortcut).
//! - `TimedOut { saw_challenge: false }` — the full timeout window
//! elapsed without any challenge markers ever being observed (no
//! container, no hidden input, no iframe). The page likely has no
//! Cloudflare gate; not a failure.
//! - `TimedOut { saw_challenge: true }` — 30s elapsed with markers
//! present but neither success state observed.
//!
//! Requires the `cloudflare` cargo feature:
//! `cargo run --example cloudflare_bypass --features cloudflare`.
use Duration;
use ;
// example boundary; users wrap in their own Error
async