1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::collections::HashMap;
9
10use crate::did::DID;
11use crate::proof::Proof;
12use crate::service::Service;
13use crate::verification_method::VerificationMethod;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct DIDDocument {
21 #[serde(rename = "@context")]
23 pub context: Vec<String>,
24
25 pub id: String,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub also_known_as: Option<Vec<String>>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub controller: Option<StringOrVec>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub verification_method: Option<Vec<VerificationMethod>>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub authentication: Option<Vec<VerificationRelationship>>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub assertion_method: Option<Vec<VerificationRelationship>>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub key_agreement: Option<Vec<VerificationRelationship>>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub capability_invocation: Option<Vec<VerificationRelationship>>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub capability_delegation: Option<Vec<VerificationRelationship>>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub service: Option<Vec<Service>>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub created: Option<DateTime<Utc>>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub updated: Option<DateTime<Utc>>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub proof: Option<OneOrMany<Proof>>,
74
75 #[serde(flatten)]
77 pub additional_properties: HashMap<String, Value>,
78}
79
80impl DIDDocument {
81 pub fn new(did: &DID) -> Self {
83 Self {
84 context: vec![
85 "https://www.w3.org/ns/did/v1".to_string(),
86 "https://w3id.org/security/suites/ed25519-2020/v1".to_string(),
87 "https://w3id.org/security/suites/x25519-2020/v1".to_string(),
88 ],
89 id: did.to_string(),
90 also_known_as: None,
91 controller: None,
92 verification_method: None,
93 authentication: None,
94 assertion_method: None,
95 key_agreement: None,
96 capability_invocation: None,
97 capability_delegation: None,
98 service: None,
99 created: Some(Utc::now()),
100 updated: None,
101 proof: None,
102 additional_properties: HashMap::new(),
103 }
104 }
105
106 pub fn add_verification_method(&mut self, method: VerificationMethod) {
108 match &mut self.verification_method {
109 Some(methods) => methods.push(method),
110 None => self.verification_method = Some(vec![method]),
111 }
112 }
113
114 pub fn add_authentication(&mut self, auth: VerificationRelationship) {
116 match &mut self.authentication {
117 Some(methods) => methods.push(auth),
118 None => self.authentication = Some(vec![auth]),
119 }
120 }
121
122 pub fn add_key_agreement(&mut self, agreement: VerificationRelationship) {
124 match &mut self.key_agreement {
125 Some(methods) => methods.push(agreement),
126 None => self.key_agreement = Some(vec![agreement]),
127 }
128 }
129
130 pub fn add_service(&mut self, service: Service) {
132 match &mut self.service {
133 Some(services) => services.push(service),
134 None => self.service = Some(vec![service]),
135 }
136 }
137
138 pub fn set_controller(&mut self, controller: impl Into<StringOrVec>) {
140 self.controller = Some(controller.into());
141 }
142
143 pub fn add_also_known_as(&mut self, identifier: String) {
145 match &mut self.also_known_as {
146 Some(ids) => ids.push(identifier),
147 None => self.also_known_as = Some(vec![identifier]),
148 }
149 }
150
151 pub fn find_verification_method(&self, id: &str) -> Option<&VerificationMethod> {
153 self.verification_method
154 .as_ref()?
155 .iter()
156 .find(|m| m.id == id || m.id.ends_with(&format!("#{id}")))
157 }
158
159 pub fn get_authentication_methods(&self) -> Vec<&VerificationMethod> {
161 let mut methods = Vec::new();
162
163 if let Some(auth_refs) = &self.authentication {
164 for auth_ref in auth_refs {
165 match auth_ref {
166 VerificationRelationship::Reference(id) => {
167 if let Some(method) = self.find_verification_method(id) {
168 methods.push(method);
169 }
170 }
171 VerificationRelationship::Embedded(method) => {
172 methods.push(method);
173 }
174 }
175 }
176 }
177
178 methods
179 }
180
181 pub fn validate(&self) -> Result<(), Vec<String>> {
183 let mut errors = Vec::new();
184
185 if self.id.is_empty() {
187 errors.push("DID Document must have an id".to_string());
188 }
189
190 if self.context.is_empty() {
191 errors.push("DID Document must have at least one context".to_string());
192 }
193
194 if DID::from_str(&self.id).is_err() {
196 errors.push(format!("Invalid DID format: {}", self.id));
197 }
198
199 if let Some(auth) = &self.authentication {
201 for auth_ref in auth {
202 if let VerificationRelationship::Reference(id) = auth_ref {
203 if self.find_verification_method(id).is_none() {
204 errors.push(format!(
205 "Authentication references non-existent verification method: {id}"
206 ));
207 }
208 }
209 }
210 }
211
212 if errors.is_empty() {
213 Ok(())
214 } else {
215 Err(errors)
216 }
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222#[serde(untagged)]
223pub enum StringOrVec {
224 String(String),
225 Vec(Vec<String>),
226}
227
228impl From<String> for StringOrVec {
229 fn from(s: String) -> Self {
230 StringOrVec::String(s)
231 }
232}
233
234impl From<Vec<String>> for StringOrVec {
235 fn from(v: Vec<String>) -> Self {
236 StringOrVec::Vec(v)
237 }
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(untagged)]
243pub enum OneOrMany<T> {
244 One(T),
245 Many(Vec<T>),
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize)]
250#[serde(untagged)]
251pub enum VerificationRelationship {
252 Reference(String),
254 Embedded(VerificationMethod),
256}
257
258impl From<String> for VerificationRelationship {
259 fn from(s: String) -> Self {
260 if s.starts_with('#') {
262 VerificationRelationship::Reference(s)
263 } else {
264 VerificationRelationship::Reference(s)
265 }
266 }
267}
268
269impl From<&str> for VerificationRelationship {
270 fn from(s: &str) -> Self {
271 VerificationRelationship::Reference(s.to_string())
272 }
273}
274
275impl From<VerificationMethod> for VerificationRelationship {
276 fn from(method: VerificationMethod) -> Self {
277 VerificationRelationship::Embedded(method)
278 }
279}
280
281use std::str::FromStr;
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286 use crate::verification_method::VerificationMethodType;
287
288 #[test]
289 fn test_did_document_creation() {
290 let did = DID::hanzo_eth("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7");
291 let mut doc = DIDDocument::new(&did);
292
293 assert_eq!(doc.id, did.to_string());
294 assert!(!doc.context.is_empty());
295
296 let vm = VerificationMethod {
298 id: format!("{}#key-1", did),
299 type_: VerificationMethodType::Ed25519VerificationKey2020,
300 controller: did.to_string(),
301 public_key_multibase: Some(
302 "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK".to_string(),
303 ),
304 ..Default::default()
305 };
306
307 doc.add_verification_method(vm.clone());
308 doc.add_authentication(format!("{}#key-1", did).into());
309
310 assert!(doc.verification_method.is_some());
311 assert!(doc.authentication.is_some());
312 assert!(doc.validate().is_ok());
313 }
314
315 #[test]
316 fn test_find_verification_method() {
317 let did = DID::hanzo_eth("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7");
318 let mut doc = DIDDocument::new(&did);
319
320 let vm_id = format!("{}#key-1", did);
321 let vm = VerificationMethod {
322 id: vm_id.clone(),
323 type_: VerificationMethodType::Ed25519VerificationKey2020,
324 controller: did.to_string(),
325 public_key_multibase: Some(
326 "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK".to_string(),
327 ),
328 ..Default::default()
329 };
330
331 doc.add_verification_method(vm);
332
333 assert!(doc.find_verification_method(&vm_id).is_some());
335
336 assert!(doc.find_verification_method("key-1").is_some());
338 }
339}