1use std::{collections::BTreeMap, str::FromStr};
2
3use iref::IriBuf;
4use serde::{Deserialize, Serialize};
5use ssi_core::one_or_many::OneOrMany;
6use ssi_verification_methods_core::{ProofPurpose, ProofPurposes};
7
8use crate::{DIDBuf, DIDURLReferenceBuf, DID, DIDURL};
9
10pub mod representation;
11pub mod resource;
12pub mod service;
13pub mod verification_method;
14
15pub use representation::Represented;
16pub use resource::{Resource, ResourceRef};
17pub use service::Service;
18pub use verification_method::DIDVerificationMethod;
19
20use self::resource::{ExtractResource, FindResource};
21
22#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
26#[serde(rename_all = "camelCase")]
27pub struct Document {
28 pub id: DIDBuf,
32
33 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 pub also_known_as: Vec<IriBuf>,
38
39 #[serde(flatten)]
46 pub verification_relationships: VerificationRelationships,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
52 pub controller: Option<OneOrMany<DIDBuf>>,
53
54 #[serde(default, skip_serializing_if = "Vec::is_empty")]
58 pub verification_method: Vec<DIDVerificationMethod>,
59
60 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub public_key: Vec<DIDVerificationMethod>,
64
65 #[serde(default, skip_serializing_if = "Vec::is_empty")]
68 pub service: Vec<Service>,
69
70 #[serde(flatten)]
73 pub property_set: BTreeMap<String, serde_json::Value>,
74}
75
76impl Document {
77 pub fn new(id: DIDBuf) -> Document {
79 Document {
80 id,
81 also_known_as: Vec::new(),
82 controller: None,
83 verification_method: Vec::new(),
84 verification_relationships: VerificationRelationships::default(),
85 service: Vec::new(),
86 property_set: BTreeMap::new(),
87 public_key: Vec::new(),
88 }
89 }
90
91 pub fn from_json(json: &str) -> Result<representation::Json, serde_json::Error> {
93 representation::Json::from_str(json)
94 }
95
96 pub fn from_json_bytes(json: &[u8]) -> Result<representation::Json, serde_json::Error> {
98 representation::Json::from_bytes(json)
99 }
100
101 pub fn from_bytes(
102 type_: representation::MediaType,
103 bytes: &[u8],
104 ) -> Result<Represented, InvalidData> {
105 match type_ {
106 representation::MediaType::Json => Ok(Represented::Json(
107 representation::Json::from_bytes(bytes).map_err(InvalidData::Json)?,
108 )),
109 representation::MediaType::JsonLd => Ok(Represented::JsonLd(
110 representation::JsonLd::from_bytes(bytes).map_err(InvalidData::JsonLd)?,
111 )),
112 }
113 }
114
115 pub fn find_resource(&self, id: &DIDURL) -> Option<ResourceRef> {
119 if self.id == *id {
120 Some(ResourceRef::Document(self))
121 } else {
122 self.verification_method
123 .find_resource(&self.id, id)
124 .or_else(|| self.verification_relationships.find_resource(&self.id, id))
125 }
126 }
127
128 pub fn into_resource(self, id: &DIDURL) -> Option<Resource> {
132 if self.id == *id {
133 Some(Resource::Document(self))
134 } else {
135 self.verification_method
136 .extract_resource(&self.id, id)
137 .or_else(|| {
138 self.verification_relationships
139 .extract_resource(&self.id, id)
140 })
141 }
142 }
143
144 pub fn service(&self, id: &str) -> Option<&Service> {
146 self.service
147 .iter()
148 .find(|s| s.id.fragment().is_some_and(|f| f.as_str() == id))
149 }
150
151 pub fn into_representation(self, options: representation::Options) -> Represented {
152 Represented::new(self, options)
153 }
154
155 pub fn into_any_verification_method(self) -> Option<DIDVerificationMethod> {
161 self.verification_method.into_iter().next()
162 }
163}
164
165#[derive(Debug, thiserror::Error)]
166#[error("invalid DID document representation data: {0}")]
167pub enum InvalidData {
168 Json(serde_json::Error),
169 JsonLd(serde_json::Error),
170}
171
172#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub struct Metadata {
176 pub deactivated: Option<bool>,
177}
178
179#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
180#[serde(rename_all = "camelCase")]
181pub struct VerificationRelationships {
182 #[serde(default, skip_serializing_if = "Vec::is_empty")]
187 pub authentication: Vec<verification_method::ValueOrReference>,
188
189 #[serde(default, skip_serializing_if = "Vec::is_empty")]
193 pub assertion_method: Vec<verification_method::ValueOrReference>,
194
195 #[serde(default, skip_serializing_if = "Vec::is_empty")]
199 pub key_agreement: Vec<verification_method::ValueOrReference>,
200
201 #[serde(default, skip_serializing_if = "Vec::is_empty")]
205 pub capability_invocation: Vec<verification_method::ValueOrReference>,
206
207 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub capability_delegation: Vec<verification_method::ValueOrReference>,
212}
213
214impl VerificationRelationships {
215 pub fn proof_purpose(&self, purpose: ProofPurpose) -> &[verification_method::ValueOrReference] {
216 match purpose {
217 ProofPurpose::Authentication => &self.authentication,
218 ProofPurpose::Assertion => &self.assertion_method,
219 ProofPurpose::KeyAgreement => &self.key_agreement,
220 ProofPurpose::CapabilityInvocation => &self.capability_invocation,
221 ProofPurpose::CapabilityDelegation => &self.capability_delegation,
222 }
223 }
224
225 pub fn contains(&self, base_did: &DID, id: &DIDURL, proof_purposes: ProofPurposes) -> bool {
226 for p in proof_purposes {
227 for v in self.proof_purpose(p) {
228 if *v.id().resolve(base_did) == *id {
229 return true;
230 }
231 }
232 }
233
234 false
235 }
236
237 pub fn from_reference(vm_reference: DIDURLReferenceBuf, proof_purposes: ProofPurposes) -> Self {
240 Self {
241 authentication: if proof_purposes.contains(ProofPurpose::Authentication) {
242 vec![verification_method::ValueOrReference::Reference(
243 vm_reference.clone(),
244 )]
245 } else {
246 Vec::new()
247 },
248 key_agreement: if proof_purposes.contains(ProofPurpose::KeyAgreement) {
249 vec![verification_method::ValueOrReference::Reference(
250 vm_reference.clone(),
251 )]
252 } else {
253 Vec::new()
254 },
255 capability_invocation: if proof_purposes.contains(ProofPurpose::CapabilityInvocation) {
256 vec![verification_method::ValueOrReference::Reference(
257 vm_reference.clone(),
258 )]
259 } else {
260 Vec::new()
261 },
262 capability_delegation: if proof_purposes.contains(ProofPurpose::CapabilityDelegation) {
263 vec![verification_method::ValueOrReference::Reference(
264 vm_reference.clone(),
265 )]
266 } else {
267 Vec::new()
268 },
269 assertion_method: if proof_purposes.contains(ProofPurpose::Assertion) {
270 vec![verification_method::ValueOrReference::Reference(
271 vm_reference,
272 )]
273 } else {
274 Vec::new()
275 },
276 }
277 }
278}
279
280impl FindResource for VerificationRelationships {
281 fn find_resource(&self, base_did: &DID, id: &DIDURL) -> Option<ResourceRef> {
282 self.authentication
283 .find_resource(base_did, id)
284 .or_else(|| self.assertion_method.find_resource(base_did, id))
285 .or_else(|| self.key_agreement.find_resource(base_did, id))
286 .or_else(|| self.capability_invocation.find_resource(base_did, id))
287 .or_else(|| self.capability_delegation.find_resource(base_did, id))
288 }
289}
290
291impl ExtractResource for VerificationRelationships {
292 fn extract_resource(self, base_did: &DID, id: &DIDURL) -> Option<Resource> {
293 self.authentication
294 .extract_resource(base_did, id)
295 .or_else(|| self.assertion_method.extract_resource(base_did, id))
296 .or_else(|| self.key_agreement.extract_resource(base_did, id))
297 .or_else(|| self.capability_invocation.extract_resource(base_did, id))
298 .or_else(|| self.capability_delegation.extract_resource(base_did, id))
299 }
300}