Skip to main content

lychee_lib/types/basic_auth/
selector.rs

1use std::str::FromStr;
2
3use serde_with::DeserializeFromStr;
4use thiserror::Error;
5
6use crate::{BasicAuthCredentials, types::basic_auth::BasicAuthCredentialsParseError};
7
8#[derive(Clone, Debug, Error, PartialEq)]
9pub enum BasicAuthSelectorParseError {
10    #[error("Empty selector input")]
11    EmptyInput,
12
13    #[error("Missing basic auth credentials or URI. Valid form is '<uri> <username>:<password>'")]
14    InvalidSyntax,
15
16    #[error(
17        "Too many space separated values. Expected 2, got {0}. Valid form is '<uri> <username>:<password>'"
18    )]
19    TooManyParts(usize),
20
21    #[error("Basic auth credentials error")]
22    BasicAuthCredentialsParseError(#[from] BasicAuthCredentialsParseError),
23
24    #[error("Regex compile error")]
25    RegexError(#[from] regex::Error),
26}
27
28/// [`BasicAuthSelector`] provides basic auth credentials for URLs which match
29/// the specified regex. This allows users to set different credentials based
30/// on the URLs they want to target.
31#[derive(Debug, Clone, DeserializeFromStr, PartialEq)]
32pub struct BasicAuthSelector {
33    /// The basic auth credentials made up of username and password
34    pub credentials: BasicAuthCredentials,
35
36    /// This regex matches URLs which will use the basic auth credentials
37    pub raw_uri_regex: String,
38}
39
40impl FromStr for BasicAuthSelector {
41    type Err = BasicAuthSelectorParseError;
42
43    fn from_str(selector: &str) -> Result<Self, Self::Err> {
44        let selector = selector.trim();
45
46        if selector.is_empty() {
47            return Err(BasicAuthSelectorParseError::EmptyInput);
48        }
49
50        let parts: Vec<_> = selector.split(' ').collect();
51
52        if parts.len() <= 1 {
53            return Err(BasicAuthSelectorParseError::InvalidSyntax);
54        }
55
56        if parts.len() > 2 {
57            return Err(BasicAuthSelectorParseError::TooManyParts(parts.len()));
58        }
59
60        Ok(Self {
61            credentials: parts[1].parse()?,
62            raw_uri_regex: parts[0].to_string(),
63        })
64    }
65}
66
67#[cfg(test)]
68mod test {
69    use super::*;
70
71    #[test]
72    fn test_valid_basic_auth_selector() {
73        let input = "http://example.com foo:bar";
74        let selector: BasicAuthSelector = input.parse().unwrap();
75
76        assert_eq!(selector.raw_uri_regex, "http://example.com".to_string());
77        assert_eq!(
78            selector.credentials,
79            BasicAuthCredentials {
80                username: "foo".to_string(),
81                password: "bar".to_string()
82            }
83        );
84    }
85
86    #[test]
87    fn test_missing_uri_basic_auth_selector() {
88        let input = "foo:bar";
89        let result = BasicAuthSelector::from_str(input);
90
91        assert!(result.is_err());
92        assert_eq!(
93            result.unwrap_err(),
94            BasicAuthSelectorParseError::InvalidSyntax
95        );
96    }
97
98    #[test]
99    fn test_missing_credentials_basic_auth_selector() {
100        let input = "https://example.com";
101        let result = BasicAuthSelector::from_str(input);
102
103        assert!(result.is_err());
104        assert_eq!(
105            result.unwrap_err(),
106            BasicAuthSelectorParseError::InvalidSyntax
107        );
108    }
109
110    #[test]
111    fn test_empty_basic_auth_selector() {
112        let input = "";
113        let result = BasicAuthSelector::from_str(input);
114
115        assert!(result.is_err());
116        assert_eq!(result.unwrap_err(), BasicAuthSelectorParseError::EmptyInput);
117
118        let input = "   ";
119        let result = BasicAuthSelector::from_str(input);
120
121        assert!(result.is_err());
122        assert_eq!(result.unwrap_err(), BasicAuthSelectorParseError::EmptyInput);
123    }
124
125    #[test]
126    fn test_too_many_parts_basic_auth_selector() {
127        let input = "";
128        let result = BasicAuthSelector::from_str(input);
129
130        assert!(result.is_err());
131        assert_eq!(result.unwrap_err(), BasicAuthSelectorParseError::EmptyInput);
132
133        let input = "   ";
134        let result = BasicAuthSelector::from_str(input);
135
136        assert!(result.is_err());
137        assert_eq!(result.unwrap_err(), BasicAuthSelectorParseError::EmptyInput);
138    }
139}