diff --git a/src/user.rs b/src/user.rs index 775c1d9..fe9ec25 100644 --- a/src/user.rs +++ b/src/user.rs @@ -22,6 +22,28 @@ pub struct User { pub handle: Option, } +fn create_user_from_did_doc(did_doc: DidDocument) -> Result { + let pds_endpoint = did_doc.get_pds_endpoint(); + let pds_uri: Option = pds_endpoint.as_deref().unwrap_or_default().parse().ok(); + let pds = pds_uri + .as_ref() + .and_then(|u| u.authority()) + .map(|a| a.host()) + .map(|s| s.to_string()); + + let handle = did_doc + .also_known_as + .and_then(|v| v.into_iter().next()) + .and_then(|s| s.strip_prefix("at://").map(str::to_string)); + let did = did_doc.id; + + // TODO: check if handle resolves to did and fill none otherwise + + let user = User { pds, did, handle }; + + Ok(user) +} + pub async fn fetch_user(server: &RelayServer, did: &str) -> Result { tracing::debug!(%did, "fetching user"); if did.starts_with("did:plc:") { @@ -58,29 +80,45 @@ pub async fn fetch_user(server: &RelayServer, did: &str) -> Result { let did_doc = serde_json::from_reader::<_, DidDocument>(body.reader()) .context("Failed to parse plc DID doc as JSON")?; - let pds_endpoint = did_doc.get_pds_endpoint(); - let pds_uri: Option = pds_endpoint.as_deref().unwrap_or_default().parse().ok(); - let pds = pds_uri - .as_ref() - .and_then(|u| u.authority()) - .map(|a| a.host()) - .map(|s| s.to_string()); - - let handle = did_doc - .also_known_as - .and_then(|v| v.into_iter().next()) - .and_then(|s| s.strip_prefix("at://").map(str::to_string)); - let did = did_doc.id; - - // TODO: check if handle resolves to did and fill none otherwise - - let user = User { pds, did, handle }; - + let user = create_user_from_did_doc(did_doc)?; + store_user(server, &user)?; + + Ok(user) + } else if let Some(domain) = did.strip_prefix("did:web:") { + let tcp_stream = TcpStream::connect((domain, 443)).await?; + let domain_tls: ServerName<'_> = ServerName::try_from(domain.to_string())?; + let tls_stream = open_tls_stream(tcp_stream, domain_tls).await?; + let io = TokioIo::new(tls_stream); + + let req = Request::builder() + .method("GET") + .uri(format!("https://{domain}/.well-known/did.json")) + .header("Host", domain.to_string()) + .body(body_empty())?; + + let (mut sender, conn) = http1::handshake::<_, HttpBody>(io).await?; + tokio::task::spawn(async move { + if let Err(err) = conn.await { + println!("Connection failed: {:?}", err); + } + }); + + let res = sender + .send_request(req) + .await + .context("Failed to send plc request")?; + if res.status() != StatusCode::OK { + bail!("server returned non-200 status for did:web document"); + } + + let body = res.collect().await?.aggregate(); + let did_doc = serde_json::from_reader::<_, DidDocument>(body.reader()) + .context("Failed to parse did:web document as JSON")?; + + let user = create_user_from_did_doc(did_doc)?; store_user(server, &user)?; Ok(user) - } else if did.starts_with("did:web:") { - todo!("resolve did web") } else { bail!("unknown did type {did}"); }