use std::sync::Arc;
use affinidi_crypto::KeyType;
use affinidi_data_integrity::{DataIntegrityError, ResolvedKey, VerificationMethodResolver};
use affinidi_did_resolver_cache_sdk::DIDCacheClient;
use affinidi_encoding::{
decode_multikey_with_codec, ED25519_PUB, P256_PUB, P384_PUB, SECP256K1_PUB, X25519_PUB,
};
use async_trait::async_trait;
#[derive(Clone)]
pub struct CachedDidResolver {
client: Arc<DIDCacheClient>,
}
impl CachedDidResolver {
pub fn new(client: Arc<DIDCacheClient>) -> Self {
Self { client }
}
pub fn client(&self) -> &Arc<DIDCacheClient> {
&self.client
}
}
#[async_trait]
impl VerificationMethodResolver for CachedDidResolver {
async fn resolve_vm(&self, vm: &str) -> Result<ResolvedKey, DataIntegrityError> {
let did = vm.split('#').next().unwrap_or(vm);
let resolve = self
.client
.resolve(did)
.await
.map_err(|e| DataIntegrityError::Resolver(format!("resolve {did}: {e}")))?;
let doc = resolve.doc;
let matching = doc
.verification_method
.iter()
.find(|m| m.id.as_str() == vm)
.ok_or_else(|| {
DataIntegrityError::Resolver(format!(
"verificationMethod {vm} not present in DID document for {did}"
))
})?;
let multibase = matching
.property_set
.get("publicKeyMultibase")
.and_then(|v| v.as_str())
.ok_or_else(|| {
DataIntegrityError::Resolver(format!(
"verificationMethod {vm} has no publicKeyMultibase (type {:?}); \
JWK-bearing methods need a custom resolver",
matching.type_
))
})?;
let (codec, public_key_bytes) = decode_multikey_with_codec(multibase)
.map_err(|e| DataIntegrityError::Resolver(format!("decode multikey: {e}")))?;
let key_type = codec_to_key_type(codec).ok_or_else(|| {
DataIntegrityError::Resolver(format!("unsupported multicodec 0x{codec:x} on {vm}"))
})?;
Ok(ResolvedKey::new(key_type, public_key_bytes))
}
}
fn codec_to_key_type(codec: u64) -> Option<KeyType> {
match codec {
c if c == ED25519_PUB => Some(KeyType::Ed25519),
c if c == X25519_PUB => Some(KeyType::X25519),
c if c == P256_PUB => Some(KeyType::P256),
c if c == P384_PUB => Some(KeyType::P384),
c if c == SECP256K1_PUB => Some(KeyType::Secp256k1),
_ => None,
}
}