diff --git a/bindings/web5_uniffi/src/web5.udl b/bindings/web5_uniffi/src/web5.udl index d16f75fa..84594d20 100644 --- a/bindings/web5_uniffi/src/web5.udl +++ b/bindings/web5_uniffi/src/web5.udl @@ -122,6 +122,7 @@ enum ResolutionMetadataError { "RepresentationNotSupported", "MethodNotSupported", "InvalidDidDocument", + "InvalidPublicKey", "InvalidDidDocumentLength", "InternalError", }; diff --git a/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt b/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt index ed39f91d..a91f2e7f 100644 --- a/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt +++ b/bound/kt/src/main/kotlin/web5/sdk/rust/UniFFI.kt @@ -6483,6 +6483,7 @@ enum class ResolutionMetadataError { REPRESENTATION_NOT_SUPPORTED, METHOD_NOT_SUPPORTED, INVALID_DID_DOCUMENT, + INVALID_PUBLIC_KEY, INVALID_DID_DOCUMENT_LENGTH, INTERNAL_ERROR; companion object diff --git a/crates/web5/src/dids/methods/did_dht/mod.rs b/crates/web5/src/dids/methods/did_dht/mod.rs index 65357cb7..4ba76c18 100644 --- a/crates/web5/src/dids/methods/did_dht/mod.rs +++ b/crates/web5/src/dids/methods/did_dht/mod.rs @@ -129,9 +129,9 @@ impl DidDht { }); } let identity_key = zbase32::decode_full_bytes_str(&did.id) - .map_err(|_| ResolutionMetadataError::InvalidDid)?; + .map_err(|_| ResolutionMetadataError::InvalidPublicKey)?; let identity_key = ed25519::public_jwk_from_bytes(&identity_key) - .map_err(|_| ResolutionMetadataError::InvalidDid)?; + .map_err(|_| ResolutionMetadataError::InvalidPublicKey)?; // construct http endpoint from gateway url and last part of did_uri let url = format!( @@ -311,3 +311,65 @@ mod tests { assert_eq!(resolved_document, did_dht.document) } } + +#[cfg(test)] +mod web5_test_vectors_did_dht { + use crate::dids::resolution::resolution_metadata::ResolutionMetadataError; + use crate::{ + dids::resolution::resolution_metadata::ResolutionMetadata, test_helpers::TestVectorFile, + }; + + #[derive(Debug, PartialEq, serde::Deserialize)] + struct VectorInput { + #[serde(rename = "didUri")] + did_uri: String, + } + + #[derive(Debug, PartialEq, serde::Deserialize)] + struct VectorOutput { + #[serde(rename = "didResolutionMetadata")] + did_resolution_metadata: ResolutionMetadata, + } + + #[test] + fn resolve() { + let path = "did_dht/resolve.json"; + let vectors: TestVectorFile = + TestVectorFile::load_from_path(path); + + for vector in vectors.vectors { + let vector_input = vector.input; + let vector_output = &vector.output; + + // As a replay attack protection protocol, if the same DID is doing a GET request within 5 minutes of each other, instead of a 404 it will start returning a 429. + // to get around this for our test we just create a new DID that is not published to get a fresh 404 for this error code + if let Some(ResolutionMetadataError::NotFound) = + vector_output.did_resolution_metadata.error + { + // TODO: According to the did dht spec a 404 should be returned when trying to resolve a DID that does not exists. Currently it incorrectly returns a 429 even on the first call. + // Uncomment this code block when resolved - https://github.com/TBD54566975/web5-rs/issues/286 + continue; + + // let private_jwk = Ed25519Generator::generate(); + // let identity_key = ed25519::to_public_jwk(&private_jwk); + // let did_dht = + // DidDht::from_identity_key(identity_key.clone()).expect("Should create did:dht"); + // + // vector_input = VectorInput{ + // did_uri: did_dht.did.uri, + // }; + } + + let resolution_result = super::DidDht::resolve(&vector_input.did_uri); + + let metadata_error = resolution_result.resolution_metadata.error.as_ref(); + let expected_error = vector_output.did_resolution_metadata.error.as_ref(); + + assert_eq!( + metadata_error, expected_error, + "Document resolution metadata does not match. Expected '{:?}' but got '{:?}'.", + expected_error, metadata_error + ); + } + } +} diff --git a/crates/web5/src/dids/methods/did_jwk.rs b/crates/web5/src/dids/methods/did_jwk.rs index 6e5e4a5c..a7076d8b 100644 --- a/crates/web5/src/dids/methods/did_jwk.rs +++ b/crates/web5/src/dids/methods/did_jwk.rs @@ -117,7 +117,7 @@ impl DidJwk { } #[cfg(test)] -mod tests { +mod web5_test_vectors_did_jwk { use crate::{ dids::{ data_model::document::Document, @@ -141,7 +141,7 @@ mod tests { } #[test] - fn test_web5_spec_did_jwk_test_vectors() { + fn resolve() { let path = "did_jwk/resolve.json"; let vectors: TestVectorFile = TestVectorFile::load_from_path(path); diff --git a/crates/web5/src/dids/resolution/resolution_metadata.rs b/crates/web5/src/dids/resolution/resolution_metadata.rs index c4d35c31..9fdc7079 100644 --- a/crates/web5/src/dids/resolution/resolution_metadata.rs +++ b/crates/web5/src/dids/resolution/resolution_metadata.rs @@ -23,6 +23,9 @@ pub enum ResolutionMetadataError { #[error("The DID Document was found but did not represent a conformant document.")] #[serde(rename = "invalidDidDocument")] InvalidDidDocument, + #[error("The DID Document does not have a valid public key.")] + #[serde(rename = "invalidPublicKey")] + InvalidPublicKey, #[error("The size of the DID Document was not within the method's acceptable limit.")] #[serde(rename = "invalidDidDocumentLength")] InvalidDidDocumentLength,