bitwarden_sm/
error.rs

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