Skip to main content

ezcapsolver/tasks/
recaptcha.rs

1use serde::Serialize;
2
3use super::ExtraFields;
4
5/// Invisible mode the service assumes for V3 when the parameter is omitted.
6///
7/// V2 defaults to `false`, which is the Rust default for `bool`; V3 does not,
8/// so this value has to be stated in both the builder and `Default`.
9const V3_DEFAULT_IS_INVISIBLE: bool = true;
10
11/// Grid size the service assumes when the parameter is omitted.
12const DEFAULT_CLASSIFICATION_SIZE: i32 = 4;
13
14/// Request parameters shared by ReCaptcha V2 task variants.
15///
16/// Build with string literals or owned strings; optional setters wrap values
17/// in `Some`, while `maybe_*` setters accept an `Option` directly.
18///
19/// ```
20/// use ezcapsolver::RecaptchaV2Task;
21///
22/// let task = RecaptchaV2Task::builder()
23///     .website_url("https://example.com")
24///     .website_key("site-key")
25///     .s("challenge-data")
26///     .build();
27/// assert_eq!(task.s.as_deref(), Some("challenge-data"));
28/// assert!(!task.is_invisible);
29/// ```
30///
31/// Required fields must be set before calling `build()`.
32///
33/// ```compile_fail
34/// use ezcapsolver::RecaptchaV2Task;
35///
36/// let task = RecaptchaV2Task::builder()
37///     .website_url("https://example.com")
38///     .build();
39/// ```
40#[derive(Debug, Clone, Serialize, Default, bon::Builder)]
41#[builder(on(String, into))]
42#[serde(remote = "Self", rename_all = "camelCase")]
43pub struct RecaptchaV2Task {
44    /// URL of the page containing the challenge.
45    #[serde(rename = "websiteURL")]
46    pub website_url: String,
47    /// ReCaptcha site key.
48    pub website_key: String,
49    /// Whether the challenge uses invisible mode.
50    #[serde(rename = "isInvisible")]
51    #[builder(default)]
52    pub is_invisible: bool,
53    /// Optional security anchor parameter.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub sa: Option<String>,
56    /// Optional challenge-bound `s` parameter.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub s: Option<String>,
59    /// Optional page title.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub website_title: Option<String>,
62    /// Optional proxy forwarded to the worker.
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub proxy: Option<String>,
65    /// Additional worker parameters.
66    #[serde(skip)]
67    #[builder(default)]
68    pub extra: ExtraFields,
69}
70
71/// Request parameters shared by ReCaptcha V3 task variants.
72#[derive(Debug, Clone, Serialize, bon::Builder)]
73#[builder(on(String, into))]
74#[serde(remote = "Self", rename_all = "camelCase")]
75pub struct RecaptchaV3Task {
76    /// URL of the page containing the challenge.
77    #[serde(rename = "websiteURL")]
78    pub website_url: String,
79    /// ReCaptcha site key.
80    pub website_key: String,
81    /// Whether the challenge uses invisible mode.
82    #[serde(rename = "isInvisible")]
83    #[builder(default = V3_DEFAULT_IS_INVISIBLE)]
84    pub is_invisible: bool,
85    /// Optional action configured by the protected page.
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub page_action: Option<String>,
88    /// Optional page title.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub website_title: Option<String>,
91    /// Optional website-specific check field.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub check_field: Option<String>,
94    /// Optional proxy forwarded to the worker.
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub proxy: Option<String>,
97    /// Additional worker parameters.
98    #[serde(skip)]
99    #[builder(default)]
100    pub extra: ExtraFields,
101}
102
103impl Default for RecaptchaV3Task {
104    fn default() -> Self {
105        Self {
106            website_url: String::new(),
107            website_key: String::new(),
108            is_invisible: V3_DEFAULT_IS_INVISIBLE,
109            page_action: None,
110            website_title: None,
111            check_field: None,
112            proxy: None,
113            extra: ExtraFields::new(),
114        }
115    }
116}
117
118/// ReCaptcha V2 image classification request.
119#[derive(Debug, Clone, Serialize, bon::Builder)]
120#[builder(on(String, into))]
121#[serde(remote = "Self", rename_all = "camelCase")]
122pub struct RecaptchaV2ClassificationTask {
123    /// Base64-encoded challenge image.
124    pub image: String,
125    /// Object identifier or classification question.
126    pub question: String,
127    /// Grid size documented by the service.
128    #[builder(default = DEFAULT_CLASSIFICATION_SIZE)]
129    pub size: i32,
130    /// Additional worker parameters.
131    #[serde(skip)]
132    #[builder(default)]
133    pub extra: ExtraFields,
134}
135
136impl Default for RecaptchaV2ClassificationTask {
137    fn default() -> Self {
138        Self {
139            image: String::new(),
140            question: String::new(),
141            size: DEFAULT_CLASSIFICATION_SIZE,
142            extra: ExtraFields::new(),
143        }
144    }
145}