Skip to main content

bitwarden_sm/
error.rs

1use thiserror::Error;
2use tracing::debug;
3use validator::ValidationErrors;
4
5#[derive(Debug, thiserror::Error)]
6pub enum SecretsManagerError {
7    #[error(transparent)]
8    Validation(ValidationError),
9    #[error(transparent)]
10    Crypto(#[from] bitwarden_crypto::CryptoError),
11    #[error(transparent)]
12    Chrono(#[from] chrono::ParseError),
13
14    #[error(transparent)]
15    Api(#[from] bitwarden_core::ApiError),
16    #[error(transparent)]
17    MissingField(#[from] bitwarden_core::MissingFieldError),
18}
19
20// Validation
21#[derive(Debug, Error)]
22pub enum ValidationError {
23    #[error("{0} must not be empty")]
24    Required(String),
25    #[error("{0} must not exceed {1} characters in length")]
26    ExceedsCharacterLength(String, u64),
27    #[error("{0} must not contain only whitespaces")]
28    OnlyWhitespaces(String),
29    #[error("Unknown validation error: {0}")]
30    Unknown(String),
31}
32
33const VALIDATION_LENGTH_CODE: &str = "length";
34const VALIDATION_ONLY_WHITESPACES_CODE: &str = "only_whitespaces";
35
36pub fn validate_only_whitespaces(value: &str) -> Result<(), validator::ValidationError> {
37    if !value.is_empty() && value.trim().is_empty() {
38        return Err(validator::ValidationError::new(
39            VALIDATION_ONLY_WHITESPACES_CODE,
40        ));
41    }
42    Ok(())
43}
44
45impl From<ValidationErrors> for ValidationError {
46    fn from(e: ValidationErrors) -> Self {
47        debug!(?e, "Validation errors");
48        for (field_name, errors) in e.field_errors() {
49            for error in errors {
50                match error.code.as_ref() {
51                    VALIDATION_LENGTH_CODE => {
52                        if error.params.contains_key("min")
53                            && error.params["min"].as_u64().expect("Min provided") == 1
54                            && error.params["value"]
55                                .as_str()
56                                .expect("Value provided")
57                                .is_empty()
58                        {
59                            return ValidationError::Required(field_name.to_string());
60                        } else if error.params.contains_key("max") {
61                            return ValidationError::ExceedsCharacterLength(
62                                field_name.to_string(),
63                                error.params["max"].as_u64().expect("Max provided"),
64                            );
65                        }
66                    }
67                    VALIDATION_ONLY_WHITESPACES_CODE => {
68                        return ValidationError::OnlyWhitespaces(field_name.to_string());
69                    }
70                    _ => {}
71                }
72            }
73        }
74        ValidationError::Unknown(format!("{e:#?}"))
75    }
76}
77
78impl From<ValidationErrors> for SecretsManagerError {
79    fn from(e: ValidationErrors) -> Self {
80        SecretsManagerError::Validation(e.into())
81    }
82}