this repo has no description
1use trust_dns_resolver::Resolver;
2use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
3
4#[derive(Debug)]
5pub struct DidDoc {
6 pub did: String,
7}
8
9fn get_txt_did(handle: &String) -> Result<String, ()> {
10 // create a txt resolver
11 let resolver = match Resolver::new(ResolverConfig::default(), ResolverOpts::default()) {
12 Ok(val) => val,
13 Err(_) => return Err(()),
14 };
15
16 // resolve _atproto.handle to a TXT record
17 let txt_res = match resolver.txt_lookup("_atproto.".to_owned() + &handle) {
18 Ok(val) => val,
19 Err(_) => return Err(()), // collect all entries and convert to strings
20 }
21 .into_iter()
22 .map(|x| x.to_string())
23 .collect::<Vec<_>>();
24
25 // filter entries which do not start with `did=`
26 let did_res = txt_res
27 .clone()
28 .extract_if(.., |x| x.starts_with("did="))
29 .collect::<Vec<_>>();
30 // only 1 did= can exist
31 // https://atproto.com/specs/handle#:~:text=If%20multiple%20valid%20records%20with%20different%20DIDs%20are%20present,%20resolution%20should%20fail.
32 if did_res.len() != 1 {
33 return Err(());
34 }
35 let did = did_res[0].clone();
36
37 return Ok(did.clone());
38}
39
40fn get_http_did(handle: &String) -> Result<String, ()> {
41 let res = match reqwest::blocking::get("https://".to_owned() + handle + "/.well-known/atproto-did") {
42 Ok(val) => val,
43 Err(_) => return Err(())
44 };
45
46 // as per spec, non 2xx code means failure
47 if !res.status().is_success() { return Err(()) }
48
49 let did_unparsed = match res.text() {
50 Ok(val) => val,
51 Err(_) => return Err(())
52 };
53
54 let did = did_unparsed.trim();
55
56 if !did.starts_with("did:") { return Err(()) };
57 return Ok(String::from(did))
58}
59
60pub fn get_did(handle: String) -> Result<DidDoc, ()> {
61 let did = if let Ok(did) = get_txt_did(&handle) {
62 did
63 } else {
64 if let Ok(did) = get_http_did(&handle) {
65 did
66 } else {
67 return Err(());
68 }
69 };
70
71 return Ok(DidDoc { did });
72}