From f0b69a3ebea2ba894df3936b404ed4a102062780 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:17:27 +0200 Subject: [PATCH] Expose iteration over verification relationship fields (#1024) --- bindings/wasm/src/did/wasm_core_document.rs | 16 ++-- bindings/wasm/src/iota/iota_document.rs | 16 ++-- identity_account/src/tests/account.rs | 4 +- identity_account/src/tests/updates.rs | 8 +- .../src/validator/credential_validator.rs | 16 ++-- .../src/validator/presentation_validator.rs | 18 ++--- identity_did/src/document/core_document.rs | 80 ++++++++++++++++++- .../src/tangle/resolver.rs | 6 +- .../src/document/iota_document.rs | 14 ++-- .../src/document/iota_document.rs | 10 +-- 10 files changed, 138 insertions(+), 50 deletions(-) diff --git a/bindings/wasm/src/did/wasm_core_document.rs b/bindings/wasm/src/did/wasm_core_document.rs index eb30fb13b6..9a8b6a1b8a 100644 --- a/bindings/wasm/src/did/wasm_core_document.rs +++ b/bindings/wasm/src/did/wasm_core_document.rs @@ -293,17 +293,23 @@ impl WasmCoreDocument { // Verification Methods // =========================================================================== - /// Returns a list of all {@link CoreVerificationMethod} in the DID Document. + /// Returns a list of all {@link CoreVerificationMethod} in the DID Document, + /// whose verification relationship matches `scope`. + /// + /// If `scope` is not set, a list over the **embedded** methods is returned. #[wasm_bindgen] - pub fn methods(&self) -> ArrayCoreVerificationMethod { - self + pub fn methods(&self, scope: Option) -> Result { + let scope: Option = scope.map(|js| js.into_serde().wasm_result()).transpose()?; + let methods = self .0 - .methods() + .methods(scope) + .into_iter() .cloned() .map(WasmCoreVerificationMethod::from) .map(JsValue::from) .collect::() - .unchecked_into::() + .unchecked_into::(); + Ok(methods) } /// Returns an array of all verification relationships. diff --git a/bindings/wasm/src/iota/iota_document.rs b/bindings/wasm/src/iota/iota_document.rs index 422f9c529b..4dd9598f79 100644 --- a/bindings/wasm/src/iota/iota_document.rs +++ b/bindings/wasm/src/iota/iota_document.rs @@ -199,17 +199,23 @@ impl WasmIotaDocument { // Verification Methods // =========================================================================== - /// Returns a list of all {@link IotaVerificationMethod} in the DID Document. + /// Returns a list of all {@link IotaVerificationMethod} in the DID Document, + /// whose verification relationship matches `scope`. + /// + /// If `scope` is not set, a list over the **embedded** methods is returned. #[wasm_bindgen] - pub fn methods(&self) -> ArrayIotaVerificationMethods { - self + pub fn methods(&self, scope: Option) -> Result { + let scope: Option = scope.map(|js| js.into_serde().wasm_result()).transpose()?; + let methods = self .0 - .methods() + .methods(scope) + .into_iter() .cloned() .map(WasmIotaVerificationMethod::from) .map(JsValue::from) .collect::() - .unchecked_into::() + .unchecked_into::(); + Ok(methods) } /// Adds a new `method` to the document in the given `scope`. diff --git a/identity_account/src/tests/account.rs b/identity_account/src/tests/account.rs index 7ccf1e9121..daaa2d6b33 100644 --- a/identity_account/src/tests/account.rs +++ b/identity_account/src/tests/account.rs @@ -159,7 +159,7 @@ async fn test_account_autopublish() { let doc = account.document(); - assert_eq!(doc.methods().count(), 1); + assert_eq!(doc.methods().len(), 1); assert_eq!(doc.service().len(), 2); for service in ["my-service", "my-other-service"] { @@ -213,7 +213,7 @@ async fn test_account_autopublish() { let doc = account.document(); assert_eq!(doc.service().len(), 0); - assert_eq!(doc.methods().count(), 2); + assert_eq!(doc.methods().len(), 2); for method in ["sign-0", "new-method"] { assert!(doc.resolve_method(method, None).is_some()); diff --git a/identity_account/src/tests/updates.rs b/identity_account/src/tests/updates.rs index 63b1309fa5..cedadecd62 100644 --- a/identity_account/src/tests/updates.rs +++ b/identity_account/src/tests/updates.rs @@ -55,7 +55,7 @@ async fn test_create_identity() -> Result<()> { let method: &IotaVerificationMethod = document.resolve_method(expected_fragment, None).unwrap(); assert_eq!(document.core_document().verification_relationships().count(), 1); - assert_eq!(document.core_document().methods().count(), 1); + assert_eq!(document.core_document().methods(None).len(), 1); let location: KeyLocation = KeyLocation::from_verification_method(method).unwrap(); @@ -204,7 +204,7 @@ async fn test_create_method_content_generate() -> Result<()> { // Still only the default relationship. assert_eq!(document.core_document().verification_relationships().count(), 1); - assert_eq!(document.core_document().methods().count(), 2); + assert_eq!(document.core_document().methods(None).len(), 2); let location: KeyLocation = KeyLocation::from_verification_method(method).unwrap(); @@ -291,7 +291,7 @@ async fn test_create_scoped_method() -> Result<()> { assert_eq!(document.core_document().verification_relationships().count(), 2); - assert_eq!(document.core_document().methods().count(), 2); + assert_eq!(document.core_document().methods(None).len(), 2); let core_doc = document.core_document(); @@ -601,7 +601,7 @@ async fn test_delete_method() -> Result<()> { // Still only the default relationship. assert_eq!(document.core_document().verification_relationships().count(), 1); - assert_eq!(document.core_document().methods().count(), 1); + assert_eq!(document.core_document().methods(None).len(), 1); // Ensure the key still exists in storage. assert!(account diff --git a/identity_credential/src/validator/credential_validator.rs b/identity_credential/src/validator/credential_validator.rs index 7d62adc216..3596fb27f1 100644 --- a/identity_credential/src/validator/credential_validator.rs +++ b/identity_credential/src/validator/credential_validator.rs @@ -408,7 +408,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); @@ -478,7 +478,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); @@ -516,7 +516,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); @@ -542,7 +542,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); @@ -589,7 +589,7 @@ mod tests { issuer_doc .signer(other_keys.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); @@ -815,7 +815,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); // the credential now has no credential subjects which is not semantically correct @@ -855,7 +855,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); // the credential now has no credential subjects which is not semantically correct @@ -894,7 +894,7 @@ mod tests { issuer_doc .signer(issuer_key.private()) .options(ProofOptions::default()) - .method(issuer_doc.methods().next().unwrap().id()) + .method(issuer_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential) .unwrap(); // the credential now has no credential subjects which is not semantically correct diff --git a/identity_credential/src/validator/presentation_validator.rs b/identity_credential/src/validator/presentation_validator.rs index ddae49f703..f84921560d 100644 --- a/identity_credential/src/validator/presentation_validator.rs +++ b/identity_credential/src/validator/presentation_validator.rs @@ -318,14 +318,14 @@ mod tests { issuer_foo_doc .signer(issuer_foo_key.private()) .options(ProofOptions::default()) - .method(issuer_foo_doc.methods().next().unwrap().id()) + .method(issuer_foo_doc.methods(None).get(0).unwrap().id()) .sign(credential_foo) .unwrap(); issuer_bar_doc .signer(issuer_bar_key.private()) .options(ProofOptions::default()) - .method(issuer_bar_doc.methods().next().unwrap().id()) + .method(issuer_bar_doc.methods(None).get(0).unwrap().id()) .sign(credential_bar) .unwrap(); setup @@ -350,7 +350,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("475a7984-1bb5-4c4c-a56f-822bccd46440".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -396,7 +396,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("some challenge".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -461,7 +461,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("some challenge".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -513,7 +513,7 @@ mod tests { issuer_bar_doc .signer(issuer_bar_key.private()) .options(ProofOptions::default()) - .method(issuer_bar_doc.methods().next().unwrap().id()) + .method(issuer_bar_doc.methods(None).get(0).unwrap().id()) .sign(&mut credential_bar) .unwrap(); @@ -525,7 +525,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("some challenge".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -619,7 +619,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("some challenge".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -692,7 +692,7 @@ mod tests { subject_foo_doc .signer(subject_foo_key.private()) .options(ProofOptions::new().challenge("some challenge".to_owned())) - .method(subject_foo_doc.methods().next().unwrap().id()) + .method(subject_foo_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); diff --git a/identity_did/src/document/core_document.rs b/identity_did/src/document/core_document.rs index 56271a7b8d..8189fb3771 100644 --- a/identity_did/src/document/core_document.rs +++ b/identity_did/src/document/core_document.rs @@ -483,10 +483,51 @@ where } } + /// Returns a `Vec` of verification method references whose verification relationship matches `scope`. + /// + /// If `scope` is `None`, an iterator over all **embedded** methods is returned. + pub fn methods(&self, scope: Option) -> Vec<&VerificationMethod> + where + D: DID, + { + if let Some(scope) = scope { + match scope { + MethodScope::VerificationMethod => self.verification_method().iter().collect(), + MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod) => self + .assertion_method() + .iter() + .filter_map(|method_ref| self.resolve_method_ref(method_ref)) + .collect(), + MethodScope::VerificationRelationship(MethodRelationship::Authentication) => self + .authentication() + .iter() + .filter_map(|method_ref| self.resolve_method_ref(method_ref)) + .collect(), + MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation) => self + .capability_delegation() + .iter() + .filter_map(|method_ref| self.resolve_method_ref(method_ref)) + .collect(), + MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation) => self + .capability_invocation() + .iter() + .filter_map(|method_ref| self.resolve_method_ref(method_ref)) + .collect(), + MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement) => self + .key_agreement() + .iter() + .filter_map(|method_ref| self.resolve_method_ref(method_ref)) + .collect(), + } + } else { + self.all_methods().collect() + } + } + /// Returns an iterator over all embedded verification methods in the DID Document. /// /// This excludes verification methods that are referenced by the DID Document. - pub fn methods(&self) -> impl Iterator> { + fn all_methods(&self) -> impl Iterator> { fn __filter_ref(method: &MethodRef) -> Option<&VerificationMethod> where D: DID, @@ -1053,8 +1094,41 @@ mod tests { let document: CoreDocument = document(); // Access methods by index. - assert_eq!(document.methods().next().unwrap().id().to_string(), "did:example:1234#key-1"); - assert_eq!(document.methods().nth(2).unwrap().id().to_string(), "did:example:1234#key-3"); + assert_eq!(document.methods(None).get(0).unwrap().id().to_string(), "did:example:1234#key-1"); + assert_eq!(document.methods(None).get(2).unwrap().id().to_string(), "did:example:1234#key-3"); + } + + #[test] + fn test_methods_scope() { + let document: CoreDocument = document(); + + // VerificationMethod + let verification_methods: Vec<&VerificationMethod> = document.methods(Some(MethodScope::VerificationMethod)); + assert_eq!( + verification_methods.get(0).unwrap().id().to_string(), + "did:example:1234#key-1" + ); + assert_eq!( + verification_methods.get(1).unwrap().id().to_string(), + "did:example:1234#key-2" + ); + assert_eq!( + verification_methods.get(2).unwrap().id().to_string(), + "did:example:1234#key-3" + ); + assert_eq!(verification_methods.len(), 3); + + // Authentication + let authentication: Vec<&VerificationMethod> = document.methods(Some(MethodScope::authentication())); + assert_eq!( + authentication.get(0).unwrap().id().to_string(), + "did:example:1234#auth-key" + ); + assert_eq!( + authentication.get(1).unwrap().id().to_string(), + "did:example:1234#key-3" + ); + assert_eq!(authentication.len(), 2); } #[test] diff --git a/identity_iota_client_legacy/src/tangle/resolver.rs b/identity_iota_client_legacy/src/tangle/resolver.rs index 22331b8951..eb2312db89 100644 --- a/identity_iota_client_legacy/src/tangle/resolver.rs +++ b/identity_iota_client_legacy/src/tangle/resolver.rs @@ -410,7 +410,7 @@ mod tests { issuer_core_doc .signer(issuer_core_key.private()) .options(ProofOptions::default()) - .method(issuer_core_doc.methods().next().unwrap().id()) + .method(issuer_core_doc.methods(None).get(0).unwrap().id()) .sign(credential_core) .unwrap(); setup @@ -436,7 +436,7 @@ mod tests { subject_doc .signer(subject_key.private()) .options(ProofOptions::new().challenge(challenge.clone())) - .method(subject_doc.methods().next().unwrap().id()) + .method(subject_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); @@ -479,7 +479,7 @@ mod tests { subject_doc .signer(subject_key.private()) .options(ProofOptions::new().challenge(challenge.clone())) - .method(subject_doc.methods().next().unwrap().id()) + .method(subject_doc.methods(None).get(0).unwrap().id()) .sign(&mut presentation) .unwrap(); diff --git a/identity_iota_core/src/document/iota_document.rs b/identity_iota_core/src/document/iota_document.rs index c4b65082e2..e60bc4bd01 100644 --- a/identity_iota_core/src/document/iota_document.rs +++ b/identity_iota_core/src/document/iota_document.rs @@ -161,9 +161,11 @@ impl IotaDocument { // Verification Methods // =========================================================================== - /// Returns an iterator over all [`IotaVerificationMethod`] in the DID Document. - pub fn methods(&self) -> impl Iterator { - self.document.methods() + /// Returns a `Vec` of verification method references whose verification relationship matches `scope`. + /// + /// If `scope` is `None`, an iterator over all **embedded** methods is returned. + pub fn methods(&self, scope: Option) -> Vec<&IotaVerificationMethod> { + self.document.methods(scope) } /// Adds a new [`IotaVerificationMethod`] to the document in the given [`MethodScope`]. @@ -506,14 +508,14 @@ mod tests { assert_eq!(doc1.id().network_str(), network.as_ref()); assert_eq!(doc1.id().tag(), placeholder.tag()); assert_eq!(doc1.id(), &placeholder); - assert_eq!(doc1.methods().count(), 0); + assert_eq!(doc1.methods(None).len(), 0); assert!(doc1.service().is_empty()); // VALID new_with_id(). let did: IotaDID = valid_did(); let doc2: IotaDocument = IotaDocument::new_with_id(did.clone()); assert_eq!(doc2.id(), &did); - assert_eq!(doc2.methods().count(), 0); + assert_eq!(doc2.methods(None).len(), 0); assert!(doc2.service().is_empty()); } @@ -528,7 +530,7 @@ mod tests { generate_method(&controller, "#auth-key"), ]; - let mut methods = document.methods(); + let mut methods = document.methods(None).into_iter(); assert_eq!(methods.next(), Some(&expected[0])); assert_eq!(methods.next(), Some(&expected[1])); assert_eq!(methods.next(), Some(&expected[2])); diff --git a/identity_iota_core_legacy/src/document/iota_document.rs b/identity_iota_core_legacy/src/document/iota_document.rs index eeb750ac32..cfaed019c8 100644 --- a/identity_iota_core_legacy/src/document/iota_document.rs +++ b/identity_iota_core_legacy/src/document/iota_document.rs @@ -273,8 +273,8 @@ impl IotaDocument { // =========================================================================== /// Returns an iterator over all [`IotaVerificationMethods`][IotaVerificationMethod] in the DID Document. - pub fn methods(&self) -> impl Iterator { - self.document.methods() + pub fn methods(&self) -> Vec<&IotaVerificationMethod> { + self.document.methods(None) } /// Adds a new [`IotaVerificationMethod`] to the document in the given [`MethodScope`]. @@ -950,7 +950,7 @@ mod tests { .build() .unwrap(); - let mut methods = document.methods(); + let mut methods = document.methods().into_iter(); assert_eq!(methods.next(), Some(expected).as_ref()); assert_eq!(methods.next(), None); @@ -967,7 +967,7 @@ mod tests { valid_verification_method(&controller, "#auth-key"), ]; - let mut methods = document.methods(); + let mut methods = document.methods().into_iter(); assert_eq!(methods.next(), Some(&expected[0])); assert_eq!(methods.next(), Some(&expected[1])); assert_eq!(methods.next(), Some(&expected[2])); @@ -1640,7 +1640,7 @@ mod tests { } // `methods` returns all embedded verification methods, so only one is expected. - assert_eq!(document.methods().count(), 1); + assert_eq!(document.methods().len(), 1); } #[test]