atrium-identity 0.1.9

Resolver library for decentralized identities in atproto using DIDs and handles
Documentation
use super::HandleResolver;
use crate::error::{Error, Result};
use atrium_api::types::string::{Did, Handle};
use atrium_common::resolver::Resolver;
use std::future::Future;

const SUBDOMAIN: &str = "_atproto";
const PREFIX: &str = "did=";

#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(Send))]
pub trait DnsTxtResolver {
    fn resolve(
        &self,
        query: &str,
    ) -> impl Future<
        Output = core::result::Result<
            Vec<String>,
            Box<dyn std::error::Error + Send + Sync + 'static>,
        >,
    >;
}

#[derive(Clone, Debug)]
pub struct DnsHandleResolverConfig<R> {
    pub dns_txt_resolver: R,
}

pub struct DnsHandleResolver<R> {
    dns_txt_resolver: R,
}

impl<R> DnsHandleResolver<R> {
    pub fn new(config: DnsHandleResolverConfig<R>) -> Self {
        Self { dns_txt_resolver: config.dns_txt_resolver }
    }
}

impl<R> Resolver for DnsHandleResolver<R>
where
    R: DnsTxtResolver + Send + Sync + 'static,
{
    type Input = Handle;
    type Output = Did;
    type Error = Error;

    async fn resolve(&self, handle: &Self::Input) -> Result<Self::Output> {
        for result in self
            .dns_txt_resolver
            .resolve(&format!("{SUBDOMAIN}.{}", handle.as_ref()))
            .await
            .map_err(Error::DnsResolver)?
        {
            if let Some(did) = result.strip_prefix(PREFIX) {
                return did.parse::<Did>().map_err(|e| Error::Did(e.to_string()));
            }
        }
        Err(Error::NotFound)
    }
}

impl<R> HandleResolver for DnsHandleResolver<R> where R: DnsTxtResolver + Send + Sync + 'static {}