Skip to main content

rocket_recaptcha_v3/
errors.rs

1use std::{
2    error::Error,
3    fmt::{Display, Error as FmtError, Formatter},
4};
5
6/// An error code reported by the `siteverify` API.
7#[derive(Debug, Clone, Eq, PartialEq)]
8#[non_exhaustive]
9pub enum ReCaptchaErrorCode {
10    /// The secret key is not set.
11    MissingInputSecret,
12    /// The secret key is invalid or malformed.
13    InvalidInputSecret,
14    /// The reCAPTCHA token is not set.
15    MissingInputResponse,
16    /// The reCAPTCHA token is invalid or malformed.
17    InvalidInputResponse,
18    /// The request is invalid or malformed.
19    BadRequest,
20    /// The reCAPTCHA token is no longer valid, because it is either too old or has been used before.
21    TimeoutOrDuplicate,
22    /// An error code this crate does not know about.
23    Other(String),
24}
25
26impl ReCaptchaErrorCode {
27    /// Return this error code as the string the `siteverify` API uses for it.
28    #[inline]
29    pub fn as_str(&self) -> &str {
30        match self {
31            ReCaptchaErrorCode::MissingInputSecret => "missing-input-secret",
32            ReCaptchaErrorCode::InvalidInputSecret => "invalid-input-secret",
33            ReCaptchaErrorCode::MissingInputResponse => "missing-input-response",
34            ReCaptchaErrorCode::InvalidInputResponse => "invalid-input-response",
35            ReCaptchaErrorCode::BadRequest => "bad-request",
36            ReCaptchaErrorCode::TimeoutOrDuplicate => "timeout-or-duplicate",
37            ReCaptchaErrorCode::Other(code) => code.as_str(),
38        }
39    }
40}
41
42impl From<String> for ReCaptchaErrorCode {
43    #[inline]
44    fn from(code: String) -> Self {
45        match code.as_str() {
46            "missing-input-secret" => ReCaptchaErrorCode::MissingInputSecret,
47            "invalid-input-secret" => ReCaptchaErrorCode::InvalidInputSecret,
48            "missing-input-response" => ReCaptchaErrorCode::MissingInputResponse,
49            "invalid-input-response" => ReCaptchaErrorCode::InvalidInputResponse,
50            "bad-request" => ReCaptchaErrorCode::BadRequest,
51            "timeout-or-duplicate" => ReCaptchaErrorCode::TimeoutOrDuplicate,
52            _ => ReCaptchaErrorCode::Other(code),
53        }
54    }
55}
56
57impl From<&str> for ReCaptchaErrorCode {
58    #[inline]
59    fn from(code: &str) -> Self {
60        ReCaptchaErrorCode::from(code.to_string())
61    }
62}
63
64impl Display for ReCaptchaErrorCode {
65    #[inline]
66    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
67        f.write_str(self.as_str())
68    }
69}
70
71#[derive(Debug, Clone)]
72#[non_exhaustive]
73/// Errors of the `ReCaptcha` struct.
74pub enum ReCaptchaError {
75    /// The `siteverify` API rejected the verification and reported these error codes.
76    ErrorCodes(Vec<ReCaptchaErrorCode>),
77    /// The `siteverify` API answered with an unexpected status code.
78    UnexpectedStatusCode(u16),
79    /// The request to the `siteverify` API could not be completed.
80    Request(String),
81    /// The answer of the `siteverify` API could not be understood.
82    UnexpectedResponse(String),
83}
84
85impl ReCaptchaError {
86    /// Return the error codes the `siteverify` API reported, which is empty for every other kind of error.
87    #[inline]
88    pub fn error_codes(&self) -> &[ReCaptchaErrorCode] {
89        match self {
90            ReCaptchaError::ErrorCodes(error_codes) => error_codes.as_slice(),
91            _ => &[],
92        }
93    }
94}
95
96impl Display for ReCaptchaError {
97    #[inline]
98    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
99        match self {
100            ReCaptchaError::ErrorCodes(error_codes) => {
101                f.write_str("The `siteverify` API reported the error codes:")?;
102
103                for error_code in error_codes {
104                    f.write_str(" ")?;
105                    Display::fmt(error_code, f)?;
106                }
107
108                Ok(())
109            },
110            ReCaptchaError::UnexpectedStatusCode(status_code) => {
111                write!(f, "The response status code of the `siteverify` API is {status_code}.")
112            },
113            ReCaptchaError::Request(text) | ReCaptchaError::UnexpectedResponse(text) => {
114                f.write_str(text)
115            },
116        }
117    }
118}
119
120impl Error for ReCaptchaError {}