did_utils/methods/key/
resolver.rs

1use async_trait::async_trait;
2
3use crate::{
4    ldmodel::Context,
5    methods::{errors::DIDResolutionError, traits::DIDResolver},
6};
7
8use crate::methods::resolution::{DIDResolutionMetadata, DIDResolutionOptions, MediaType, ResolutionOutput};
9
10use crate::methods::DidKey;
11
12#[async_trait]
13impl DIDResolver for DidKey {
14    /// Resolves a DID using the did:key method.
15    ///
16    /// # Arguments
17    ///
18    /// * `did` - The DID address to resolve.
19    ///
20    /// # Returns
21    ///
22    /// A `ResolutionOutput` struct containing the resolved DID document and metadata.
23    async fn resolve(&self, did: &str, _options: &DIDResolutionOptions) -> ResolutionOutput {
24        let context = Context::SingleString(String::from("https://w3id.org/did-resolution/v1"));
25
26        match self.expand(did) {
27            Ok(diddoc) => ResolutionOutput {
28                context,
29                did_document: Some(diddoc),
30                did_resolution_metadata: Some(DIDResolutionMetadata {
31                    error: None,
32                    content_type: Some(MediaType::DidLdJson.to_string()),
33                    additional_properties: None,
34                }),
35                did_document_metadata: None,
36                additional_properties: None,
37            },
38            Err(err) => ResolutionOutput {
39                context,
40                did_document: None,
41                did_resolution_metadata: Some(DIDResolutionMetadata {
42                    error: Some(if !did.starts_with("did:key:") {
43                        DIDResolutionError::MethodNotSupported
44                    } else {
45                        err
46                    }),
47                    content_type: None,
48                    additional_properties: None,
49                }),
50                did_document_metadata: None,
51                additional_properties: None,
52            },
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use crate::{crypto::PublicKeyFormat, methods::resolution::DereferencingOptions};
61    use serde_json::Value;
62
63    #[async_std::test]
64    async fn test_did_key_resolution_with_encryption_derivation() {
65        let did_method = DidKey::new_full(true, PublicKeyFormat::default());
66
67        let did = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
68        let expected: Value = serde_json::from_str(
69            r#"{
70                "@context": "https://w3id.org/did-resolution/v1",
71                "didDocument": {
72                    "@context": [
73                        "https://www.w3.org/ns/did/v1",
74                        "https://w3id.org/security/suites/ed25519-2020/v1",
75                        "https://w3id.org/security/suites/x25519-2020/v1"
76                    ],
77                    "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
78                    "verificationMethod": [
79                        {
80                            "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
81                            "type": "Ed25519VerificationKey2020",
82                            "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
83                            "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
84                        },
85                        {
86                            "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p",
87                            "type": "X25519KeyAgreementKey2020",
88                            "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
89                            "publicKeyMultibase": "z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p"
90                        }
91                    ],
92                    "authentication": ["did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"],
93                    "assertionMethod": ["did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"],
94                    "capabilityDelegation": ["did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"],
95                    "capabilityInvocation": ["did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"],
96                    "keyAgreement": ["did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p"]
97                },
98                "didResolutionMetadata": {
99                    "contentType": "application/did+ld+json"
100                },
101                "didDocumentMetadata": null
102            }"#,
103        )
104        .unwrap();
105
106        let output = did_method.resolve(did, &DIDResolutionOptions::default()).await;
107
108        assert_eq!(
109            json_canon::to_string(&output).unwrap(),   //
110            json_canon::to_string(&expected).unwrap(), //
111        );
112    }
113
114    #[async_std::test]
115    async fn test_did_key_resolution_fails_as_expected() {
116        let did_method = DidKey::default();
117
118        let did = "did:key:Z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
119        let expected: Value = serde_json::from_str(
120            r#"{
121                "@context": "https://w3id.org/did-resolution/v1",
122                "didDocument": null,
123                "didResolutionMetadata": {
124                    "error": "invalidDid"
125                },
126                "didDocumentMetadata": null
127            }"#,
128        )
129        .unwrap();
130
131        let output = did_method.resolve(did, &DIDResolutionOptions::default()).await;
132
133        assert_eq!(
134            json_canon::to_string(&output).unwrap(),   //
135            json_canon::to_string(&expected).unwrap(), //
136        );
137    }
138
139    #[async_std::test]
140    async fn test_dereferencing_did_key_url() {
141        let did_method = DidKey::new_full(true, PublicKeyFormat::default());
142
143        let did_url = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p";
144        let expected: Value = serde_json::from_str(
145            r#"{
146                "@context": "https://w3id.org/did-resolution/v1",
147                "content": {
148                    "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p",
149                    "type": "X25519KeyAgreementKey2020",
150                    "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
151                    "publicKeyMultibase": "z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p"
152                },
153                "dereferencingMetadata": {
154                    "contentType": "application/json"
155                },
156                "contentMetadata": null
157            }"#,
158        )
159        .unwrap();
160
161        let output = did_method.dereference(did_url, &DereferencingOptions::default()).await;
162
163        assert_eq!(
164            json_canon::to_string(&output).unwrap(),   //
165            json_canon::to_string(&expected).unwrap(), //
166        );
167    }
168}