resolve did:web users

main
Charlotte Som 2024-11-26 22:42:58 +02:00
parent c9e4db5f91
commit 28ecfd6851
1 changed files with 58 additions and 20 deletions

View File

@ -22,6 +22,28 @@ pub struct User {
pub handle: Option<String>,
}
fn create_user_from_did_doc(did_doc: DidDocument) -> Result<User> {
let pds_endpoint = did_doc.get_pds_endpoint();
let pds_uri: Option<Uri> = 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<User> {
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<User> {
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<Uri> = 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}");
}