use anyhow::Result;
use async_trait::async_trait;
use chromiumoxide::Page;
use super::{parse_detection_result, CaptchaInfo, Detector};
pub struct ChallengePageDetector;
impl ChallengePageDetector {
pub const JS: &'static str = r#"(function() {
if (document.title.includes('Just a moment') ||
document.title.includes('Attention Required') ||
document.querySelector('#challenge-running, #challenge-form, .cf-browser-verification')) {
return { kind: 'turnstile', site_key: null, container: '#challenge-form' };
}
return { kind: 'none', site_key: null, container: null };
})()"#;
}
#[async_trait]
impl Detector for ChallengePageDetector {
fn name(&self) -> &'static str {
"challenge_page"
}
fn priority(&self) -> i32 {
5
}
async fn detect(&self, page: &Page) -> Result<Option<CaptchaInfo>> {
let raw = page.evaluate(Self::JS).await?;
let val = raw.into_value::<serde_json::Value>()?;
Ok(parse_detection_result(val))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn challenge_page_detector_js_has_selectors() {
assert!(ChallengePageDetector::JS.contains("Just a moment"));
assert!(ChallengePageDetector::JS.contains("Attention Required"));
assert!(ChallengePageDetector::JS.contains("#challenge-running"));
assert!(ChallengePageDetector::JS.contains("#challenge-form"));
}
}