1use std::collections::BTreeMap;
2
3use iref::IriRefBuf;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7 document::{self, representation, DIDVerificationMethod, InvalidData},
8 DIDMethod, Document, PrimaryDIDURL, VerificationMethodDIDResolver, DID, DIDURL,
9};
10
11mod composition;
12mod dereference;
13mod static_resolver;
14
15pub use dereference::*;
16pub use static_resolver::StaticDIDResolver;
17
18#[cfg(feature = "http")]
19mod http;
20
21#[cfg(feature = "http")]
22pub use http::*;
23
24pub const MEDIA_TYPE_URL: &str = "text/url";
27
28#[derive(Debug, thiserror::Error)]
32pub enum Error {
33 #[error("DID method `{0}` not supported")]
35 MethodNotSupported(String),
36
37 #[error("DID document not found")]
39 NotFound,
40
41 #[error("no representation specified")]
43 NoRepresentation,
44
45 #[error("DID representation `{0}` not supported")]
47 RepresentationNotSupported(String),
48
49 #[error(transparent)]
51 InvalidData(InvalidData),
52
53 #[error("invalid method specific identifier: {0}")]
55 InvalidMethodSpecificId(String),
56
57 #[error("invalid options")]
59 InvalidOptions,
60
61 #[error("DID resolver internal error: {0}")]
63 Internal(String),
64}
65
66impl Error {
67 pub fn internal(error: impl ToString) -> Self {
69 Self::Internal(error.to_string())
70 }
71
72 pub fn kind(&self) -> ErrorKind {
74 match self {
75 Self::MethodNotSupported(_) => ErrorKind::MethodNotSupported,
76 Self::NotFound => ErrorKind::NotFound,
77 Self::NoRepresentation => ErrorKind::NoRepresentation,
78 Self::RepresentationNotSupported(_) => ErrorKind::RepresentationNotSupported,
79 Self::InvalidData(_) => ErrorKind::InvalidData,
80 Self::InvalidMethodSpecificId(_) => ErrorKind::InvalidMethodSpecificId,
81 Self::InvalidOptions => ErrorKind::InvalidOptions,
82 Self::Internal(_) => ErrorKind::Internal,
83 }
84 }
85}
86
87impl From<representation::Unknown> for Error {
88 fn from(value: representation::Unknown) -> Self {
89 Self::RepresentationNotSupported(value.0)
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
97pub enum ErrorKind {
98 MethodNotSupported,
99 NotFound,
100 NoRepresentation,
101 RepresentationNotSupported,
102 InvalidData,
103 InvalidMethodSpecificId,
104 InvalidOptions,
105 Internal,
106}
107
108pub trait DIDResolverByMethod {
109 type MethodResolver: DIDMethodResolver;
110
111 fn get_method(&self, method_name: &str) -> Option<&Self::MethodResolver>;
113
114 fn supports_method(&self, method_name: &str) -> bool {
115 self.get_method(method_name).is_some()
116 }
117}
118
119impl<T: DIDResolverByMethod> DIDResolver for T {
120 async fn resolve_representation<'a>(
121 &'a self,
122 did: &'a DID,
123 options: Options,
124 ) -> Result<Output<Vec<u8>>, Error> {
125 match self.get_method(did.method_name()) {
126 Some(m) => {
127 m.resolve_method_representation(did.method_specific_id(), options)
128 .await
129 }
130 None => Err(Error::MethodNotSupported(did.method_name().to_string())),
131 }
132 }
133}
134
135pub trait DIDResolver {
148 #[allow(async_fn_in_trait)]
155 async fn resolve_representation<'a>(
156 &'a self,
157 did: &'a DID,
158 options: Options,
159 ) -> Result<Output<Vec<u8>>, Error>;
160
161 #[allow(async_fn_in_trait)]
168 async fn resolve_with<'a>(&'a self, did: &'a DID, options: Options) -> Result<Output, Error> {
169 let output = self.resolve_representation(did, options).await?;
170 match &output.metadata.content_type {
171 None => Err(Error::NoRepresentation),
172 Some(ty) => {
173 let ty: representation::MediaType = ty.parse()?;
174 output
175 .try_map(|bytes| Document::from_bytes(ty, &bytes))
176 .map_err(Error::InvalidData)
177 }
178 }
179 }
180
181 #[allow(async_fn_in_trait)]
188 async fn resolve<'a>(&'a self, did: &'a DID) -> Result<Output, Error> {
189 self.resolve_with(did, Options::default()).await
190 }
191
192 #[allow(async_fn_in_trait)]
200 async fn resolve_into_any_verification_method<'a>(
201 &'a self,
202 did: &'a DID,
203 ) -> Result<Option<DIDVerificationMethod>, Error> {
204 Ok(self
205 .resolve(did)
206 .await?
207 .document
208 .into_document()
209 .into_any_verification_method())
210 }
211
212 #[allow(async_fn_in_trait)]
217 async fn dereference_primary<'a>(
218 &'a self,
219 primary_did_url: &'a PrimaryDIDURL,
220 ) -> Result<DerefOutput<PrimaryContent>, DerefError> {
221 self.dereference_primary_with(primary_did_url, Options::default())
222 .await
223 }
224
225 #[allow(async_fn_in_trait)]
230 async fn dereference_primary_with<'a>(
231 &'a self,
232 primary_did_url: &'a PrimaryDIDURL,
233 mut resolve_options: Options,
234 ) -> Result<DerefOutput<PrimaryContent>, DerefError> {
235 resolve_options.extend(match primary_did_url.query() {
237 Some(query) => serde_urlencoded::from_str(query.as_str()).unwrap(),
238 None => Options::default(),
239 });
240
241 let parameters = resolve_options.parameters.clone();
242
243 let resolution_output = self
244 .resolve_with(primary_did_url.did(), resolve_options)
245 .await?;
246
247 dereference_primary_resource(self, primary_did_url, parameters, resolution_output).await
248 }
249
250 #[allow(async_fn_in_trait)]
261 async fn dereference_primary_with_path_or_query<'a>(
262 &'a self,
263 _primary_did_url: &'a PrimaryDIDURL,
264 ) -> Result<DerefOutput<PrimaryContent>, DerefError> {
265 Err(DerefError::NotFound)
266 }
267
268 #[allow(async_fn_in_trait)]
273 async fn dereference_with<'a>(
274 &'a self,
275 did_url: &'a DIDURL,
276 options: Options,
277 ) -> Result<DerefOutput, DerefError> {
278 let (primary_did_url, fragment) = did_url.without_fragment();
279 let primary_deref_output = self
280 .dereference_primary_with(primary_did_url, options)
281 .await?;
282 match fragment {
284 Some(fragment) => {
285 dereference_secondary_resource(primary_did_url, fragment, primary_deref_output)
286 }
287 None => Ok(primary_deref_output.cast()),
288 }
289 }
290
291 #[allow(async_fn_in_trait)]
296 async fn dereference<'a>(&'a self, did_url: &'a DIDURL) -> Result<DerefOutput, DerefError> {
297 self.dereference_with(did_url, Options::default()).await
298 }
299
300 fn into_vm_resolver_with<M>(self, options: Options) -> VerificationMethodDIDResolver<Self, M>
306 where
307 Self: Sized,
308 {
309 VerificationMethodDIDResolver::new_with_options(self, options)
310 }
311
312 fn into_vm_resolver<M>(self) -> VerificationMethodDIDResolver<Self, M>
321 where
322 Self: Sized,
323 {
324 VerificationMethodDIDResolver::new(self)
325 }
326}
327
328pub trait DIDMethodResolver: DIDMethod {
329 fn method_name(&self) -> &str {
331 Self::DID_METHOD_NAME
332 }
333
334 #[allow(async_fn_in_trait)]
341 async fn resolve_method_representation<'a>(
342 &'a self,
343 method_specific_id: &'a str,
344 options: Options,
345 ) -> Result<Output<Vec<u8>>, Error>;
346}
347
348impl<T: DIDMethodResolver> DIDMethodResolver for &T {
349 fn method_name(&self) -> &str {
350 T::method_name(*self)
351 }
352
353 async fn resolve_method_representation<'b>(
354 &'b self,
355 method_specific_id: &'b str,
356 options: Options,
357 ) -> Result<Output<Vec<u8>>, Error> {
358 T::resolve_method_representation(*self, method_specific_id, options).await
359 }
360}
361
362impl<T: DIDMethodResolver> DIDResolverByMethod for T {
363 type MethodResolver = Self;
364
365 fn get_method(&self, method_name: &str) -> Option<&Self> {
366 if self.method_name() == method_name {
367 Some(self)
368 } else {
369 None
370 }
371 }
372}
373
374#[derive(Debug, Clone)]
375pub struct Output<T = document::Represented> {
376 pub document: T,
377 pub document_metadata: document::Metadata,
378 pub metadata: Metadata,
379}
380
381impl<T> Output<T> {
382 pub fn from_content(content: T, content_type: Option<String>) -> Self {
383 Self::new(
384 content,
385 document::Metadata::default(),
386 Metadata::from_content_type(content_type),
387 )
388 }
389
390 pub fn new(document: T, document_metadata: document::Metadata, metadata: Metadata) -> Self {
391 Self {
392 document,
393 document_metadata,
394 metadata,
395 }
396 }
397
398 pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<Output<U>, E> {
399 Ok(Output {
400 document: f(self.document)?,
401 document_metadata: self.document_metadata,
402 metadata: self.metadata,
403 })
404 }
405}
406
407#[derive(Debug, Default, Clone, Serialize, Deserialize)]
409pub struct Options {
410 #[serde(skip_serializing_if = "Option::is_none")]
414 pub accept: Option<representation::MediaType>,
415
416 #[serde(flatten)]
418 pub parameters: Parameters,
419}
420
421impl Options {
422 pub fn extend(&mut self, other: Self) {
423 if let Some(value) = other.accept {
424 self.accept = Some(value)
425 }
426
427 self.parameters.extend(other.parameters)
428 }
429}
430
431#[derive(Debug, Default, Clone, Serialize, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct Parameters {
439 #[serde(skip_serializing_if = "Option::is_none")]
441 pub service: Option<String>, #[serde(skip_serializing_if = "Option::is_none", alias = "relative-ref")]
446 pub relative_ref: Option<IriRefBuf>, #[serde(skip_serializing_if = "Option::is_none")]
451 pub version_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
456 pub version_time: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
463 pub hl: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
469 pub public_key_format: Option<String>,
470
471 #[serde(flatten)]
473 pub additional: BTreeMap<String, Parameter>,
474}
475
476impl Parameters {
477 pub fn extend(&mut self, other: Self) {
478 if let Some(value) = other.service {
479 self.service = Some(value)
480 }
481
482 if let Some(value) = other.relative_ref {
483 self.relative_ref = Some(value)
484 }
485
486 if let Some(value) = other.version_id {
487 self.version_id = Some(value)
488 }
489
490 if let Some(value) = other.version_time {
491 self.version_time = Some(value)
492 }
493
494 if let Some(value) = other.hl {
495 self.hl = Some(value)
496 }
497
498 if let Some(value) = other.public_key_format {
499 self.public_key_format = Some(value)
500 }
501
502 self.additional.extend(other.additional);
503 }
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize)]
508#[serde(untagged)]
509pub enum Parameter {
510 Null,
511 String(String),
512 List(Vec<String>),
513}
514
515impl Parameter {
516 pub fn as_string(&self) -> Option<&str> {
517 match self {
518 Self::String(s) => Some(s),
519 _ => None,
520 }
521 }
522
523 pub fn into_string(self) -> Result<String, Self> {
524 match self {
525 Self::String(s) => Ok(s),
526 other => Err(other),
527 }
528 }
529}
530
531#[derive(Debug, Default, Clone, Serialize)]
533#[serde(rename_all = "camelCase")]
534pub struct Metadata {
535 pub content_type: Option<String>,
536}
537
538impl Metadata {
539 pub fn from_content_type(content_type: Option<String>) -> Self {
540 Self { content_type }
541 }
542}