xdid_core/
document.rs

1use jose_jwk::Jwk;
2use serde::{Deserialize, Serialize};
3use serde_with::{serde_as, skip_serializing_none};
4use smol_str::SmolStr;
5
6use crate::{
7    did::Did,
8    did_url::{DidUrl, RelativeDidUrl},
9};
10
11#[skip_serializing_none]
12#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
13#[serde(rename_all = "camelCase")]
14#[serde_as]
15pub struct Document {
16    pub id: Did,
17    pub also_known_as: Option<Vec<String>>,
18    #[serde_as(as = "Option<OneOrMany<_>>")]
19    pub controller: Option<Vec<Did>>,
20    pub verification_method: Option<Vec<VerificationMethodMap>>,
21    pub authentication: Option<Vec<VerificationMethod>>,
22    pub assertion_method: Option<Vec<VerificationMethod>>,
23    pub key_agreement: Option<Vec<VerificationMethod>>,
24    pub capability_invocation: Option<Vec<VerificationMethod>>,
25    pub capability_delegation: Option<Vec<VerificationMethod>>,
26    pub service: Option<Vec<ServiceEndpoint>>,
27}
28
29impl Document {
30    /// Returns the verification method that the provided [`DidUrl`] is
31    /// referencing, restricted to a given [`VerificationRole`].
32    #[must_use]
33    pub fn resolve_verification_method_url(
34        &self,
35        url: &DidUrl,
36        role: VerificationRole,
37    ) -> Option<VerificationMethodMap> {
38        let methods = match role {
39            VerificationRole::Assertion => self.assertion_method.as_deref(),
40            VerificationRole::Authentication => self.authentication.as_deref(),
41            VerificationRole::CapabilityDelegation => self.capability_delegation.as_deref(),
42            VerificationRole::CapabilityInvocation => self.capability_invocation.as_deref(),
43            VerificationRole::KeyAgreement => self.key_agreement.as_deref(),
44        }
45        .unwrap_or_default();
46
47        for method in methods {
48            if let Some(resolved) = self.resolve_verification_method(method)
49                && resolved.id == *url
50            {
51                return Some(resolved);
52            }
53        }
54
55        None
56    }
57
58    /// Resolves a [`VerificationMethod`] to its [`VerificationMethodMap`].
59    /// For embedded maps, returns the map directly. For URL references,
60    /// resolves them against this document's `verification_method` array.
61    #[must_use]
62    pub fn resolve_verification_method(
63        &self,
64        method: &VerificationMethod,
65    ) -> Option<VerificationMethodMap> {
66        match method {
67            VerificationMethod::Map(map) => Some(*map.clone()),
68            VerificationMethod::RelativeUrl(relative_url) => {
69                self.resolve_relative_url(relative_url)
70            }
71            VerificationMethod::Url(url) => {
72                // Only resolve if the URL references this document.
73                if url.did == self.id
74                    && let Some(relative_url) = url.to_relative()
75                {
76                    return self.resolve_relative_url(&relative_url);
77                }
78                // TODO: Support additional DID resolution?
79                None
80            }
81        }
82    }
83
84    fn resolve_relative_url(&self, url: &RelativeDidUrl) -> Option<VerificationMethodMap> {
85        for method in self.verification_method.as_deref().unwrap_or_default() {
86            if method.id.to_relative().as_ref() == Some(url) {
87                return Some(method.clone());
88            }
89        }
90
91        None
92    }
93}
94
95#[derive(Debug, Copy, Clone, PartialEq, Eq)]
96pub enum VerificationRole {
97    Assertion,
98    Authentication,
99    CapabilityDelegation,
100    CapabilityInvocation,
101    KeyAgreement,
102}
103
104#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
105#[serde(untagged)]
106pub enum VerificationMethod {
107    Map(Box<VerificationMethodMap>),
108    RelativeUrl(RelativeDidUrl),
109    Url(DidUrl),
110}
111
112#[skip_serializing_none]
113#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
114pub struct VerificationMethodMap {
115    pub id: DidUrl,
116    pub controller: Did,
117    #[serde(rename = "type")]
118    pub typ: SmolStr,
119    pub public_key_jwk: Option<Jwk>,
120    /// Multibase encoded public key.
121    pub public_key_multibase: Option<String>,
122}
123
124#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
125#[serde_as]
126pub struct ServiceEndpoint {
127    pub id: String,
128    #[serde(rename = "type")]
129    #[serde_as(as = "OneOrMany<_>")]
130    pub typ: Vec<String>,
131}