use async_trait::async_trait;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChallengeKind {
pub vendor: &'static str,
pub sub_kind: &'static str,
}
impl ChallengeKind {
pub const fn new(vendor: &'static str, sub_kind: &'static str) -> Self {
Self { vendor, sub_kind }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolveOutcome {
NotApplicable,
InProgress,
Solved,
Unsolvable,
}
#[async_trait(?Send)]
pub trait ChallengeSolver: Send + Sync {
fn name(&self) -> &'static str;
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
async fn observe_response(&self, host: &str, resp: &crate::net::Response) {}
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
fn prepare_request(&self, host: &str, headers: &mut Vec<(String, String)>) {}
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
fn detect(&self, resp: &crate::net::Response, html: &str) -> Option<ChallengeKind> {
None
}
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
async fn solve(
&self,
page: &mut crate::Page,
client: &crate::net::HttpClient,
kind: ChallengeKind,
) -> SolveOutcome {
SolveOutcome::NotApplicable
}
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
fn relax_response_csp(&self, html: &str) -> bool {
false
}
#[allow(
unused_variables,
reason = "default trait-method body ignores params; concrete ChallengeSolver impls use them"
)]
fn solved_signal(&self, cookies: &str, body: &str) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
struct PassiveSolver;
#[async_trait(?Send)]
impl ChallengeSolver for PassiveSolver {
fn name(&self) -> &'static str {
"passive"
}
}
#[test]
fn challenge_kind_basic() {
let k = ChallengeKind::new("akamai-bmp", "sensor-data");
assert_eq!(k.vendor, "akamai-bmp");
assert_eq!(k.sub_kind, "sensor-data");
assert_eq!(k.clone(), k);
}
#[test]
fn passive_solver_has_safe_defaults() {
let s = PassiveSolver;
assert_eq!(s.name(), "passive");
let mut headers: Vec<(String, String)> = Vec::new();
s.prepare_request("example.com", &mut headers);
assert!(headers.is_empty());
assert!(!s.solved_signal("foo=bar", "<html></html>"));
}
#[test]
fn solver_object_safety() {
let _v: Vec<std::sync::Arc<dyn ChallengeSolver>> = vec![std::sync::Arc::new(PassiveSolver)];
}
}