Skip to main content

edgee_sdk/
token.rs

1/// Generates a token from a hostname.
2///
3/// This function generates a token by computing the MD5 hash of the provided hostname
4/// and formatting it as a lowercase hexadecimal string.
5///
6/// # Arguments
7///
8/// * `hostname` - A string slice containing the hostname to generate a token for
9///
10/// # Returns
11///
12/// * `String` - The generated token as a 32-character lowercase hexadecimal string
13///
14/// # Examples
15///
16/// ```
17/// let hostname = "example.com";
18/// let token = edgee_sdk::token::generate(hostname);
19/// assert_eq!(token.len(), 32);
20/// ```
21pub fn generate(hostname: &str) -> String {
22    format!("{:x}", md5::compute(hostname))
23}
24
25/// Validates a token from an authorization header against a hostname.
26///
27/// This function checks if a given authorization header contains a valid token for the specified hostname.
28/// The token must be in the format "Bearer <token>" where <token> is a 32-character MD5 hash of the hostname.
29///
30/// # Arguments
31///
32/// * `hostname` - A string slice containing the hostname to validate against
33/// * `authorization_header` - A string slice containing the full authorization header value
34///
35/// # Returns
36///
37/// * `bool` - Returns true if the token is valid for the hostname, false otherwise
38///
39/// # Examples
40///
41/// ```
42/// let hostname = "example.com";
43/// let auth_header = "Bearer d41d8cd98f00b204e9800998ecf8427e";
44/// let is_valid = edgee_sdk::token::validate(hostname, auth_header);
45/// ```
46pub fn validate(hostname: &str, authorization_header: &str) -> bool {
47    if !authorization_header.starts_with("Bearer ") {
48        return false;
49    }
50
51    let token = &authorization_header["Bearer ".len()..];
52
53    if token.len() != 32 {
54        return false;
55    }
56
57    let token_md5 = format!("{:x}", md5::compute(hostname));
58
59    token == token_md5
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_generate_token() {
68        let hostname = "example.com";
69        let token = generate(hostname);
70
71        // Check token length
72        assert_eq!(token.len(), 32);
73
74        // Check deterministic output
75        assert_eq!(generate(hostname), generate(hostname));
76
77        // Known value test
78        assert_eq!(
79            generate("test.com"),
80            "c97c1b3671fef2055e175ca2154d217a".to_string()
81        );
82    }
83
84    #[test]
85    fn test_validate_token() {
86        let hostname = "example.com";
87        let token = generate(hostname);
88        let valid_header = format!("Bearer {}", token);
89
90        // Test valid token
91        assert!(validate(hostname, &valid_header));
92
93        // Test invalid bearer format
94        assert!(!validate(hostname, &token));
95        assert!(!validate(hostname, "bearer 123"));
96        assert!(!validate(hostname, "Basic 123"));
97        assert!(!validate(hostname, ""));
98
99        // Test invalid token length
100        assert!(!validate(hostname, "Bearer 123"));
101        assert!(!validate(
102            hostname,
103            "Bearer 123456789012345678901234567890123"
104        )); // 33 chars
105
106        // Test wrong token
107        assert!(!validate(
108            hostname,
109            "Bearer 0000000000000000000000000000000"
110        ));
111
112        // Test different hostname
113        let other_token = generate("other.com");
114        assert!(!validate(hostname, &format!("Bearer {}", other_token)));
115    }
116}