did_utils/methods/
utils.rs1use std::collections::HashMap;
2
3use url::Url;
4
5use super::errors::DIDResolutionError;
6
7pub type ParsedDIDUrl = (String, HashMap<String, String>, Option<String>);
8
9pub(super) fn parse_did_url(did_url: &str) -> Result<ParsedDIDUrl, DIDResolutionError> {
11 if !did_url.starts_with("did:") {
12 return Err(DIDResolutionError::InvalidDidUrlPrefix);
13 }
14
15 if did_url.contains("%%") {
16 return Err(DIDResolutionError::InvalidDidUrlFormat);
17 }
18
19 if did_url.split(':').filter(|x| !x.is_empty()).count() < 3 {
20 return Err(DIDResolutionError::DidUrlPartLengthTooShort);
21 }
22
23 let url = format!("scheme://{}", did_url.replace(':', "%%"));
24 let url = Url::parse(&url).map_err(|_| DIDResolutionError::InvalidDidUrlFormat)?;
25 let domain = url.domain().ok_or(DIDResolutionError::InvalidDidUrlFormat)?;
26
27 let did = domain.replace("%%", ":");
28 if did.split(':').filter(|x| !x.is_empty()).count() < 3 {
29 return Err(DIDResolutionError::DidUrlPartLengthTooShort);
30 }
31
32 let query = url.query_pairs().map(|(key, val)| (key.to_string(), val.to_string())).collect();
33 let fragment = url.fragment().map(|x| x.to_string());
34
35 Ok((did, query, fragment))
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn test_did_url_parsing() {
44 let (did, query, fragment) = parse_did_url("did:key:abcd?x=a&y=b#f").unwrap();
45 assert_eq!(did, "did:key:abcd");
46 assert_eq!(query.get("x").unwrap(), "a");
47 assert_eq!(query.get("y").unwrap(), "b");
48 assert_eq!(fragment.unwrap(), "f");
49
50 let (did, query, fragment) = parse_did_url("did:web:example.com:a:b?m=hello+world").unwrap();
51 assert_eq!(did, "did:web:example.com:a:b");
52 assert_eq!(query.get("m").unwrap(), "hello world");
53 assert!(fragment.is_none());
54 }
55
56 #[test]
57 fn test_did_url_parsing_fails_as_expected() {
58 let entries = [
59 ("dxd:key:abcd", DIDResolutionError::InvalidDidUrlPrefix),
60 ("did:key:a%%d", DIDResolutionError::InvalidDidUrlFormat),
61 ("did:key", DIDResolutionError::DidUrlPartLengthTooShort),
62 ("did:key:", DIDResolutionError::DidUrlPartLengthTooShort),
63 ("did:key:?k=v", DIDResolutionError::DidUrlPartLengthTooShort),
64 ("did:key:ab\\cd", DIDResolutionError::InvalidDidUrlFormat),
65 ("did:key:abcd|80", DIDResolutionError::InvalidDidUrlFormat),
66 ("did:key:abcd[80]", DIDResolutionError::InvalidDidUrlFormat),
67 ];
68
69 for (did_url, err) in entries {
70 assert_eq!(parse_did_url(did_url).unwrap_err(), err);
71 }
72 }
73}