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 #[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 #[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 if url.did == self.id
74 && let Some(relative_url) = url.to_relative()
75 {
76 return self.resolve_relative_url(&relative_url);
77 }
78 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 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}