1use std::{error::Error, fmt};
2
3use zeroize::Zeroizing;
4
5pub const MAX_CAPTCHA_TOKEN_LEN: usize = 16 * 1024;
7
8pub struct CaptchaToken(Zeroizing<String>);
13
14impl CaptchaToken {
15 pub fn new(value: impl Into<String>) -> Result<Self, CaptchaTokenError> {
22 let value = value.into();
23 if value.is_empty() {
24 return Err(CaptchaTokenError::Empty);
25 }
26 if value.len() > MAX_CAPTCHA_TOKEN_LEN {
27 return Err(CaptchaTokenError::TooLong);
28 }
29 Ok(Self(Zeroizing::new(value)))
30 }
31
32 #[allow(dead_code)]
34 pub(crate) fn expose(&self) -> &str {
35 self.0.as_str()
36 }
37}
38
39impl fmt::Debug for CaptchaToken {
40 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
41 formatter.write_str("CaptchaToken([REDACTED])")
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[non_exhaustive]
48pub enum CaptchaTokenError {
49 Empty,
51 TooLong,
53}
54
55impl fmt::Display for CaptchaTokenError {
56 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57 let message = match self {
58 Self::Empty => "CAPTCHA token must not be empty",
59 Self::TooLong => "CAPTCHA token is too long",
60 };
61 formatter.write_str(message)
62 }
63}
64
65impl Error for CaptchaTokenError {}