identity_document/document/
core_document.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use core::convert::TryInto as _;
5use core::fmt::Display;
6use core::fmt::Formatter;
7use std::collections::HashMap;
8use std::convert::Infallible;
9
10use identity_did::DIDJwk;
11use identity_verification::jose::jwk::Jwk;
12use identity_verification::jose::jws::DecodedJws;
13use identity_verification::jose::jws::Decoder;
14use identity_verification::jose::jws::JwsVerifier;
15use serde::Serialize;
16
17use identity_core::common::Object;
18use identity_core::common::OneOrSet;
19use identity_core::common::OrderedSet;
20use identity_core::common::Url;
21use identity_core::convert::FmtJson;
22use serde::Serializer;
23
24use crate::document::DocumentBuilder;
25use crate::error::Error;
26use crate::error::Result;
27use crate::service::Service;
28use crate::utils::DIDUrlQuery;
29use crate::utils::Queryable;
30use crate::verifiable::JwsVerificationOptions;
31use identity_did::CoreDID;
32use identity_did::DIDUrl;
33use identity_verification::MethodRef;
34use identity_verification::MethodRelationship;
35use identity_verification::MethodScope;
36use identity_verification::VerificationMethod;
37
38#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
39#[rustfmt::skip]
40pub(crate) struct CoreDocumentData
41{
42  pub(crate) id: CoreDID,
43  #[serde(skip_serializing_if = "Option::is_none")]
44  pub(crate) controller: Option<OneOrSet<CoreDID>>,
45  #[serde(default = "Default::default", rename = "alsoKnownAs", skip_serializing_if = "OrderedSet::is_empty")]
46  pub(crate) also_known_as: OrderedSet<Url>,
47  #[serde(default = "Default::default", rename = "verificationMethod", skip_serializing_if = "OrderedSet::is_empty")]
48  pub(crate) verification_method: OrderedSet<VerificationMethod>,
49  #[serde(default = "Default::default", skip_serializing_if = "OrderedSet::is_empty")]
50  pub(crate) authentication: OrderedSet<MethodRef>,
51  #[serde(default = "Default::default", rename = "assertionMethod", skip_serializing_if = "OrderedSet::is_empty")]
52  pub(crate) assertion_method: OrderedSet<MethodRef>,
53  #[serde(default = "Default::default", rename = "keyAgreement", skip_serializing_if = "OrderedSet::is_empty")]
54  pub(crate) key_agreement: OrderedSet<MethodRef>,
55  #[serde(default = "Default::default", rename = "capabilityDelegation", skip_serializing_if = "OrderedSet::is_empty")]
56  pub(crate) capability_delegation: OrderedSet<MethodRef>,
57  #[serde(default = "Default::default", rename = "capabilityInvocation", skip_serializing_if = "OrderedSet::is_empty")]
58  pub(crate) capability_invocation: OrderedSet<MethodRef>,
59  #[serde(default = "Default::default", skip_serializing_if = "OrderedSet::is_empty")]
60  pub(crate) service: OrderedSet<Service>,
61  #[serde(flatten)]
62  pub(crate) properties: Object,
63}
64
65impl CoreDocumentData {
66  /// Checks the following:
67  /// - There are no scoped method references to an embedded method in the document
68  /// - The ids of verification methods (scoped/embedded or general purpose) and services are unique across the
69  ///   document.
70  fn check_id_constraints(&self) -> Result<()> {
71    let max_unique_method_ids = self.verification_method.len()
72      + self.authentication.len()
73      + self.assertion_method.len()
74      + self.key_agreement.len()
75      + self.capability_delegation.len()
76      + self.capability_invocation.len();
77
78    // Value = true => the identifier belongs to an embedded method, false means it belongs to a method reference or a
79    // general purpose verification method
80    let mut method_identifiers: HashMap<&DIDUrl, bool> = HashMap::with_capacity(max_unique_method_ids);
81
82    for (id, is_embedded) in self
83      .authentication
84      .iter()
85      .chain(self.assertion_method.iter())
86      .chain(self.key_agreement.iter())
87      .chain(self.capability_delegation.iter())
88      .chain(self.capability_invocation.iter())
89      .map(|method_ref| match method_ref {
90        MethodRef::Embed(_) => (method_ref.id(), true),
91        MethodRef::Refer(_) => (method_ref.id(), false),
92      })
93    {
94      if let Some(previous) = method_identifiers.insert(id, is_embedded) {
95        match previous {
96          // An embedded method with the same id has previously been encountered
97          true => {
98            return Err(Error::InvalidDocument(
99              "attempted to construct document with a duplicated or aliased embedded method",
100              None,
101            ));
102          }
103          // A method reference to the identifier has previously been encountered
104          false => {
105            if is_embedded {
106              return Err(Error::InvalidDocument(
107                "attempted to construct document with an aliased embedded method",
108                None,
109              ));
110            }
111          }
112        }
113      }
114    }
115
116    for method_id in self.verification_method.iter().map(|method| method.id()) {
117      if method_identifiers
118        .insert(method_id, false)
119        .filter(|value| *value)
120        .is_some()
121      {
122        return Err(Error::InvalidDocument(
123          "attempted to construct document with a duplicated embedded method",
124          None,
125        ));
126      }
127    }
128
129    for service_id in self.service.iter().map(|service| service.id()) {
130      if method_identifiers.contains_key(service_id) {
131        return Err(Error::InvalidDocument(
132          "attempted to construct document with a service identifier shared with a verification method",
133          None,
134        ));
135      }
136    }
137
138    Ok(())
139  }
140
141  // Apply the provided fallible functions to the DID components of `id`, `controller`, methods and services
142  // respectively.
143  fn try_map<F, G, H, L, E>(
144    self,
145    id_map: F,
146    mut controller_map: G,
147    mut method_map: H,
148    mut services_map: L,
149  ) -> Result<Self, E>
150  where
151    F: FnOnce(CoreDID) -> std::result::Result<CoreDID, E>,
152    G: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
153    H: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
154    L: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
155  {
156    let current_data = self;
157    // Update `id`
158    let id = id_map(current_data.id)?;
159    // Update controllers
160    let controller = if let Some(controllers) = current_data.controller {
161      Some(controllers.try_map(&mut controller_map)?)
162    } else {
163      None
164    };
165
166    // Update methods
167
168    let verification_method = current_data
169      .verification_method
170      .into_iter()
171      .map(|method| method.try_map(&mut method_map))
172      .collect::<Result<_, E>>()?;
173
174    let authentication = current_data
175      .authentication
176      .into_iter()
177      .map(|method_ref| method_ref.try_map(&mut method_map))
178      .collect::<Result<_, E>>()?;
179
180    let assertion_method = current_data
181      .assertion_method
182      .into_iter()
183      .map(|method_ref| method_ref.try_map(&mut method_map))
184      .collect::<Result<_, E>>()?;
185
186    let key_agreement = current_data
187      .key_agreement
188      .into_iter()
189      .map(|method_ref| method_ref.try_map(&mut method_map))
190      .collect::<Result<_, E>>()?;
191
192    let capability_delegation = current_data
193      .capability_delegation
194      .into_iter()
195      .map(|method_ref| method_ref.try_map(&mut method_map))
196      .collect::<Result<_, E>>()?;
197
198    let capability_invocation = current_data
199      .capability_invocation
200      .into_iter()
201      .map(|method_ref| method_ref.try_map(&mut method_map))
202      .collect::<Result<_, E>>()?;
203
204    // Update services
205    let service = current_data
206      .service
207      .into_iter()
208      .map(|service| service.try_map(&mut services_map))
209      .collect::<Result<_, E>>()?;
210
211    Ok(CoreDocumentData {
212      id,
213      controller,
214      also_known_as: current_data.also_known_as,
215      verification_method,
216      authentication,
217      assertion_method,
218      key_agreement,
219      capability_delegation,
220      capability_invocation,
221      service,
222      properties: current_data.properties,
223    })
224  }
225}
226
227/// A DID Document.
228///
229/// [Specification](https://www.w3.org/TR/did-core/#did-document-properties)
230#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
231#[rustfmt::skip]
232#[serde(try_from = "CoreDocumentData")]
233pub struct CoreDocument
234{
235  pub(crate) data: CoreDocumentData, 
236}
237
238//Forward serialization to inner
239impl Serialize for CoreDocument {
240  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
241  where
242    S: Serializer,
243  {
244    self.data.serialize(serializer)
245  }
246}
247
248// Workaround for lifetime issues with a mutable reference to self preventing closures from being used.
249macro_rules! method_ref_mut_helper {
250  ($doc:ident, $method: ident, $query: ident) => {
251    match $doc.data.$method.query_mut($query.into())? {
252      MethodRef::Embed(method) => Some(method),
253      MethodRef::Refer(ref did) => $doc.data.verification_method.query_mut(did),
254    }
255  };
256}
257
258impl CoreDocument {
259  /// Creates a [`DocumentBuilder`] to configure a new `CoreDocument`.
260  ///
261  /// This is the same as [`DocumentBuilder::new`].
262  pub fn builder(properties: Object) -> DocumentBuilder {
263    DocumentBuilder::new(properties)
264  }
265
266  /// Returns a new `CoreDocument` based on the [`DocumentBuilder`] configuration.
267  pub fn from_builder(builder: DocumentBuilder) -> Result<Self> {
268    Self::try_from(CoreDocumentData {
269      id: builder.id.ok_or(Error::InvalidDocument("missing id", None))?,
270      controller: Some(builder.controller)
271        .filter(|controllers| !controllers.is_empty())
272        .map(TryFrom::try_from)
273        .transpose()
274        .map_err(|err| Error::InvalidDocument("controller", Some(err)))?,
275      also_known_as: builder
276        .also_known_as
277        .try_into()
278        .map_err(|err| Error::InvalidDocument("also_known_as", Some(err)))?,
279      verification_method: builder
280        .verification_method
281        .try_into()
282        .map_err(|err| Error::InvalidDocument("verification_method", Some(err)))?,
283      authentication: builder
284        .authentication
285        .try_into()
286        .map_err(|err| Error::InvalidDocument("authentication", Some(err)))?,
287      assertion_method: builder
288        .assertion_method
289        .try_into()
290        .map_err(|err| Error::InvalidDocument("assertion_method", Some(err)))?,
291      key_agreement: builder
292        .key_agreement
293        .try_into()
294        .map_err(|err| Error::InvalidDocument("key_agreement", Some(err)))?,
295      capability_delegation: builder
296        .capability_delegation
297        .try_into()
298        .map_err(|err| Error::InvalidDocument("capability_delegation", Some(err)))?,
299      capability_invocation: builder
300        .capability_invocation
301        .try_into()
302        .map_err(|err| Error::InvalidDocument("capability_invocation", Some(err)))?,
303      service: builder
304        .service
305        .try_into()
306        .map_err(|err| Error::InvalidDocument("service", Some(err)))?,
307      properties: builder.properties,
308    })
309  }
310
311  /// Returns a reference to the `CoreDocument` id.
312  pub fn id(&self) -> &CoreDID {
313    &self.data.id
314  }
315
316  /// Returns a mutable reference to the `CoreDocument` id.
317  ///
318  /// # Warning
319  ///
320  /// Changes to the identifier can drastically alter the results of
321  /// [`Self::resolve_method`](CoreDocument::resolve_method()),
322  /// [`Self::resolve_service`](CoreDocument::resolve_service()) and the related [DID URL dereferencing](https://w3c-ccg.github.io/did-resolution/#dereferencing) algorithm.
323  pub fn id_mut_unchecked(&mut self) -> &mut CoreDID {
324    &mut self.data.id
325  }
326
327  /// Returns a reference to the `CoreDocument` controller.
328  pub fn controller(&self) -> Option<&OneOrSet<CoreDID>> {
329    self.data.controller.as_ref()
330  }
331
332  /// Returns a mutable reference to the `CoreDocument` controller.
333  pub fn controller_mut(&mut self) -> &mut Option<OneOrSet<CoreDID>> {
334    &mut self.data.controller
335  }
336
337  /// Returns a reference to the `CoreDocument` alsoKnownAs set.
338  pub fn also_known_as(&self) -> &OrderedSet<Url> {
339    &self.data.also_known_as
340  }
341
342  /// Returns a mutable reference to the `CoreDocument` alsoKnownAs set.
343  pub fn also_known_as_mut(&mut self) -> &mut OrderedSet<Url> {
344    &mut self.data.also_known_as
345  }
346
347  /// Returns a reference to the `CoreDocument` verificationMethod set.
348  pub fn verification_method(&self) -> &OrderedSet<VerificationMethod> {
349    &self.data.verification_method
350  }
351
352  /// Returns a reference to the `CoreDocument` authentication set.
353  pub fn authentication(&self) -> &OrderedSet<MethodRef> {
354    &self.data.authentication
355  }
356
357  /// Returns a reference to the `CoreDocument` assertionMethod set.
358  pub fn assertion_method(&self) -> &OrderedSet<MethodRef> {
359    &self.data.assertion_method
360  }
361
362  /// Returns a reference to the `CoreDocument` keyAgreement set.
363  pub fn key_agreement(&self) -> &OrderedSet<MethodRef> {
364    &self.data.key_agreement
365  }
366
367  /// Returns a reference to the `CoreDocument` capabilityDelegation set.
368  pub fn capability_delegation(&self) -> &OrderedSet<MethodRef> {
369    &self.data.capability_delegation
370  }
371
372  /// Returns a reference to the `CoreDocument` capabilityInvocation set.
373  pub fn capability_invocation(&self) -> &OrderedSet<MethodRef> {
374    &self.data.capability_invocation
375  }
376
377  /// Returns a reference to the `CoreDocument` service set.
378  pub fn service(&self) -> &OrderedSet<Service> {
379    &self.data.service
380  }
381
382  /// # Warning
383  ///
384  /// Changing a service's identifier can drastically alter the results of
385  /// [`Self::resolve_service`](CoreDocument::resolve_service()) and the related [DID URL dereferencing](https://w3c-ccg.github.io/did-resolution/#dereferencing) algorithm.
386  pub fn service_mut_unchecked(&mut self) -> &mut OrderedSet<Service> {
387    &mut self.data.service
388  }
389
390  /// Returns a reference to the custom `CoreDocument` properties.
391  pub fn properties(&self) -> &Object {
392    &self.data.properties
393  }
394
395  /// Returns a mutable reference to the custom `CoreDocument` properties.
396  ///
397  /// # Warning
398  ///
399  /// The properties returned are not checked against the standard fields in a [`CoreDocument`]. Incautious use can have
400  /// undesired consequences such as key collision when attempting to serialize the document or distinct resources (such
401  /// as services and methods) being identified by the same DID URL.  
402  pub fn properties_mut_unchecked(&mut self) -> &mut Object {
403    &mut self.data.properties
404  }
405
406  /// Adds a new [`VerificationMethod`] to the document in the given [`MethodScope`].
407  ///
408  /// # Errors
409  ///
410  /// Returns an error if a method or service with the same fragment already exists.
411  pub fn insert_method(&mut self, method: VerificationMethod, scope: MethodScope) -> Result<()> {
412    // Check that the method identifier is not already in use by an existing method or service.
413    //
414    // NOTE: this check cannot be relied upon if the document contains methods or services whose ids are
415    // of the form <did different from this document's>#<fragment>.
416    if self.resolve_method(method.id(), None).is_some() || self.service().query(method.id()).is_some() {
417      return Err(Error::MethodInsertionError);
418    }
419    match scope {
420      MethodScope::VerificationMethod => self.data.verification_method.append(method),
421      MethodScope::VerificationRelationship(MethodRelationship::Authentication) => {
422        self.data.authentication.append(MethodRef::Embed(method))
423      }
424      MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod) => {
425        self.data.assertion_method.append(MethodRef::Embed(method))
426      }
427      MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement) => {
428        self.data.key_agreement.append(MethodRef::Embed(method))
429      }
430      MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation) => {
431        self.data.capability_delegation.append(MethodRef::Embed(method))
432      }
433      MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation) => {
434        self.data.capability_invocation.append(MethodRef::Embed(method))
435      }
436    };
437
438    Ok(())
439  }
440
441  /// Removes and returns the [`VerificationMethod`] identified by `did_url` from the document.
442  ///
443  /// # Note
444  ///
445  /// All _references to the method_ found in the document will be removed.
446  /// This includes cases where the reference is to a method contained in another DID document.
447  pub fn remove_method(&mut self, did_url: &DIDUrl) -> Option<VerificationMethod> {
448    self.remove_method_and_scope(did_url).map(|(method, _scope)| method)
449  }
450
451  /// Removes and returns the [`VerificationMethod`] from the document. The [`MethodScope`] under which the method was
452  /// found is appended to the second position of the returned tuple.
453  ///
454  /// # Note
455  ///
456  /// All _references to the method_ found in the document will be removed.
457  /// This includes cases where the reference is to a method contained in another DID document.
458  pub fn remove_method_and_scope(&mut self, did_url: &DIDUrl) -> Option<(VerificationMethod, MethodScope)> {
459    for (method_ref, scope) in [
460      self.data.authentication.remove(did_url).map(|method_ref| {
461        (
462          method_ref,
463          MethodScope::VerificationRelationship(MethodRelationship::Authentication),
464        )
465      }),
466      self.data.assertion_method.remove(did_url).map(|method_ref| {
467        (
468          method_ref,
469          MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod),
470        )
471      }),
472      self.data.key_agreement.remove(did_url).map(|method_ref| {
473        (
474          method_ref,
475          MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement),
476        )
477      }),
478      self.data.capability_delegation.remove(did_url).map(|method_ref| {
479        (
480          method_ref,
481          MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation),
482        )
483      }),
484      self.data.capability_invocation.remove(did_url).map(|method_ref| {
485        (
486          method_ref,
487          MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation),
488        )
489      }),
490    ]
491    .into_iter()
492    .flatten()
493    {
494      if let (MethodRef::Embed(embedded_method), scope) = (method_ref, scope) {
495        // embedded methods cannot be referenced, or be in the set of general purpose verification methods hence the
496        // search is complete
497        return Some((embedded_method, scope));
498      }
499    }
500
501    self
502      .data
503      .verification_method
504      .remove(did_url)
505      .map(|method| (method, MethodScope::VerificationMethod))
506  }
507
508  /// Adds a new [`Service`] to the document.
509  ///
510  /// # Errors
511  ///
512  /// Returns an error if there already exists a service or verification method with the same identifier.
513  pub fn insert_service(&mut self, service: Service) -> Result<()> {
514    let service_id = service.id();
515    let id_exists = self
516      .verification_relationships()
517      .map(|method_ref| method_ref.id())
518      .chain(self.verification_method().iter().map(|method| method.id()))
519      .any(|id| id == service_id);
520
521    ((!id_exists) && self.data.service.append(service))
522      .then_some(())
523      .ok_or(Error::InvalidServiceInsertion)
524  }
525
526  /// Removes and returns a [`Service`] from the document if it exists.
527  pub fn remove_service(&mut self, id: &DIDUrl) -> Option<Service> {
528    self.data.service.remove(id)
529  }
530
531  /// Attaches the relationship to the method resolved by `method_query`.
532  ///
533  /// # Errors
534  ///
535  /// Returns an error if the method does not exist or if it is embedded.
536  /// To convert an embedded method into a generic verification method, remove it first
537  /// and insert it with [`MethodScope::VerificationMethod`].
538  pub fn attach_method_relationship<'query, Q>(
539    &mut self,
540    method_query: Q,
541    relationship: MethodRelationship,
542  ) -> Result<bool>
543  where
544    Q: Into<DIDUrlQuery<'query>>,
545  {
546    let method_query: DIDUrlQuery<'query> = method_query.into();
547
548    match self.resolve_method(method_query.clone(), Some(MethodScope::VerificationMethod)) {
549      None => match self.resolve_method(method_query, None) {
550        Some(_) => Err(Error::InvalidMethodEmbedded),
551        None => Err(Error::MethodNotFound),
552      },
553      Some(method) => {
554        let method_ref = MethodRef::Refer(method.id().clone());
555
556        let was_attached = match relationship {
557          MethodRelationship::Authentication => self.data.authentication.append(method_ref),
558          MethodRelationship::AssertionMethod => self.data.assertion_method.append(method_ref),
559          MethodRelationship::KeyAgreement => self.data.key_agreement.append(method_ref),
560          MethodRelationship::CapabilityDelegation => self.data.capability_delegation.append(method_ref),
561          MethodRelationship::CapabilityInvocation => self.data.capability_invocation.append(method_ref),
562        };
563
564        Ok(was_attached)
565      }
566    }
567  }
568
569  /// Detaches the relationship from the method resolved by `method_query`.
570  /// Returns `true` if the relationship was found and removed, `false` otherwise.
571  ///
572  /// # Errors
573  ///
574  /// Returns an error if the method does not exist or is embedded.
575  /// To remove an embedded method, use [`Self::remove_method`].
576  ///
577  /// # Note
578  ///
579  /// If the method is referenced in the given scope, but the document does not contain the referenced verification
580  /// method, then the reference will persist in the document (i.e. it is not removed).
581  pub fn detach_method_relationship<'query, Q>(
582    &mut self,
583    method_query: Q,
584    relationship: MethodRelationship,
585  ) -> Result<bool>
586  where
587    Q: Into<DIDUrlQuery<'query>>,
588  {
589    let method_query: DIDUrlQuery<'query> = method_query.into();
590    match self.resolve_method(method_query.clone(), Some(MethodScope::VerificationMethod)) {
591      None => match self.resolve_method(method_query, None) {
592        Some(_) => Err(Error::InvalidMethodEmbedded),
593        None => Err(Error::MethodNotFound),
594      },
595      Some(method) => {
596        let did_url: DIDUrl = method.id().clone();
597
598        let was_detached = match relationship {
599          MethodRelationship::Authentication => self.data.authentication.remove(&did_url),
600          MethodRelationship::AssertionMethod => self.data.assertion_method.remove(&did_url),
601          MethodRelationship::KeyAgreement => self.data.key_agreement.remove(&did_url),
602          MethodRelationship::CapabilityDelegation => self.data.capability_delegation.remove(&did_url),
603          MethodRelationship::CapabilityInvocation => self.data.capability_invocation.remove(&did_url),
604        };
605
606        Ok(was_detached.is_some())
607      }
608    }
609  }
610
611  /// Returns a `Vec` of verification method references whose verification relationship matches `scope`.
612  ///
613  /// If `scope` is `None`, an iterator over all **embedded** methods is returned.
614  pub fn methods(&self, scope: Option<MethodScope>) -> Vec<&VerificationMethod> {
615    if let Some(scope) = scope {
616      match scope {
617        MethodScope::VerificationMethod => self.verification_method().iter().collect(),
618        MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod) => self
619          .assertion_method()
620          .iter()
621          .filter_map(|method_ref| self.resolve_method_ref(method_ref))
622          .collect(),
623        MethodScope::VerificationRelationship(MethodRelationship::Authentication) => self
624          .authentication()
625          .iter()
626          .filter_map(|method_ref| self.resolve_method_ref(method_ref))
627          .collect(),
628        MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation) => self
629          .capability_delegation()
630          .iter()
631          .filter_map(|method_ref| self.resolve_method_ref(method_ref))
632          .collect(),
633        MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation) => self
634          .capability_invocation()
635          .iter()
636          .filter_map(|method_ref| self.resolve_method_ref(method_ref))
637          .collect(),
638        MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement) => self
639          .key_agreement()
640          .iter()
641          .filter_map(|method_ref| self.resolve_method_ref(method_ref))
642          .collect(),
643      }
644    } else {
645      self.all_methods().collect()
646    }
647  }
648
649  /// Returns an iterator over all embedded verification methods in the DID Document.
650  ///
651  /// This excludes verification methods that are referenced by the DID Document.
652  fn all_methods(&self) -> impl Iterator<Item = &VerificationMethod> {
653    fn __filter_ref(method: &MethodRef) -> Option<&VerificationMethod> {
654      match method {
655        MethodRef::Embed(method) => Some(method),
656        MethodRef::Refer(_) => None,
657      }
658    }
659
660    self
661      .data
662      .verification_method
663      .iter()
664      .chain(self.data.authentication.iter().filter_map(__filter_ref))
665      .chain(self.data.assertion_method.iter().filter_map(__filter_ref))
666      .chain(self.data.key_agreement.iter().filter_map(__filter_ref))
667      .chain(self.data.capability_delegation.iter().filter_map(__filter_ref))
668      .chain(self.data.capability_invocation.iter().filter_map(__filter_ref))
669  }
670
671  /// Returns an iterator over all verification relationships.
672  ///
673  /// This includes embedded and referenced [`VerificationMethods`](VerificationMethod).
674  pub fn verification_relationships(&self) -> impl Iterator<Item = &MethodRef> {
675    self
676      .data
677      .authentication
678      .iter()
679      .chain(self.data.assertion_method.iter())
680      .chain(self.data.key_agreement.iter())
681      .chain(self.data.capability_delegation.iter())
682      .chain(self.data.capability_invocation.iter())
683  }
684
685  /// Returns the first [`VerificationMethod`] with an `id` property matching the
686  /// provided `method_query` and the verification relationship specified by `scope` if present.
687  // NOTE: This method demonstrates unexpected behaviour in the edge cases where the document contains methods
688  // whose ids are of the form <did different from this document's>#<fragment>.
689  pub fn resolve_method<'query, 'me, Q>(
690    &'me self,
691    method_query: Q,
692    scope: Option<MethodScope>,
693  ) -> Option<&'me VerificationMethod>
694  where
695    Q: Into<DIDUrlQuery<'query>>,
696  {
697    match scope {
698      Some(scope) => {
699        let resolve_ref_helper = |method_ref: &'me MethodRef| self.resolve_method_ref(method_ref);
700
701        match scope {
702          MethodScope::VerificationMethod => self.data.verification_method.query(method_query.into()),
703          MethodScope::VerificationRelationship(MethodRelationship::Authentication) => self
704            .data
705            .authentication
706            .query(method_query.into())
707            .and_then(resolve_ref_helper),
708          MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod) => self
709            .data
710            .assertion_method
711            .query(method_query.into())
712            .and_then(resolve_ref_helper),
713          MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement) => self
714            .data
715            .key_agreement
716            .query(method_query.into())
717            .and_then(resolve_ref_helper),
718          MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation) => self
719            .data
720            .capability_delegation
721            .query(method_query.into())
722            .and_then(resolve_ref_helper),
723          MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation) => self
724            .data
725            .capability_invocation
726            .query(method_query.into())
727            .and_then(resolve_ref_helper),
728        }
729      }
730      None => self.resolve_method_inner(method_query.into()),
731    }
732  }
733
734  /// Returns a mutable reference to the first [`VerificationMethod`] with an `id` property
735  /// matching the provided `method_query`.
736  ///
737  /// # Warning
738  ///
739  /// Incorrect use of this method can lead to distinct document resources being identified by the same DID URL.
740  // NOTE: This method demonstrates unexpected behaviour in the edge cases where the document contains methods
741  // whose ids are of the form <did different from this document's>#<fragment>.
742  pub fn resolve_method_mut<'query, 'me, Q>(
743    &'me mut self,
744    method_query: Q,
745    scope: Option<MethodScope>,
746  ) -> Option<&'me mut VerificationMethod>
747  where
748    Q: Into<DIDUrlQuery<'query>>,
749  {
750    match scope {
751      Some(scope) => match scope {
752        MethodScope::VerificationMethod => self.data.verification_method.query_mut(method_query.into()),
753        MethodScope::VerificationRelationship(MethodRelationship::Authentication) => {
754          method_ref_mut_helper!(self, authentication, method_query)
755        }
756        MethodScope::VerificationRelationship(MethodRelationship::AssertionMethod) => {
757          method_ref_mut_helper!(self, assertion_method, method_query)
758        }
759        MethodScope::VerificationRelationship(MethodRelationship::KeyAgreement) => {
760          method_ref_mut_helper!(self, key_agreement, method_query)
761        }
762        MethodScope::VerificationRelationship(MethodRelationship::CapabilityDelegation) => {
763          method_ref_mut_helper!(self, capability_delegation, method_query)
764        }
765        MethodScope::VerificationRelationship(MethodRelationship::CapabilityInvocation) => {
766          method_ref_mut_helper!(self, capability_invocation, method_query)
767        }
768      },
769      None => self.resolve_method_mut_inner(method_query.into()),
770    }
771  }
772
773  /// Returns the first [`Service`] with an `id` property matching the provided `service_query`, if present.
774  // NOTE: This method demonstrates unexpected behavior in the edge cases where the document contains
775  // services whose ids are of the form <did different from this document's>#<fragment>.
776  pub fn resolve_service<'query, 'me, Q>(&'me self, service_query: Q) -> Option<&'me Service>
777  where
778    Q: Into<DIDUrlQuery<'query>>,
779  {
780    self.service().query(service_query.into())
781  }
782
783  #[doc(hidden)]
784  pub fn resolve_method_ref<'a>(&'a self, method_ref: &'a MethodRef) -> Option<&'a VerificationMethod> {
785    match method_ref {
786      MethodRef::Embed(method) => Some(method),
787      MethodRef::Refer(did) => self.data.verification_method.query(did),
788    }
789  }
790
791  fn resolve_method_inner(&self, query: DIDUrlQuery<'_>) -> Option<&VerificationMethod> {
792    let mut method: Option<&MethodRef> = None;
793
794    if method.is_none() {
795      method = self.data.authentication.query(query.clone());
796    }
797
798    if method.is_none() {
799      method = self.data.assertion_method.query(query.clone());
800    }
801
802    if method.is_none() {
803      method = self.data.key_agreement.query(query.clone());
804    }
805
806    if method.is_none() {
807      method = self.data.capability_delegation.query(query.clone());
808    }
809
810    if method.is_none() {
811      method = self.data.capability_invocation.query(query.clone());
812    }
813
814    match method {
815      Some(MethodRef::Embed(method)) => Some(method),
816      Some(MethodRef::Refer(did)) => self.data.verification_method.query(&did.to_string()),
817      None => self.data.verification_method.query(query),
818    }
819  }
820
821  fn resolve_method_mut_inner(&mut self, query: DIDUrlQuery<'_>) -> Option<&mut VerificationMethod> {
822    let mut method: Option<&mut MethodRef> = None;
823
824    if method.is_none() {
825      method = self.data.authentication.query_mut(query.clone());
826    }
827
828    if method.is_none() {
829      method = self.data.assertion_method.query_mut(query.clone());
830    }
831
832    if method.is_none() {
833      method = self.data.key_agreement.query_mut(query.clone());
834    }
835
836    if method.is_none() {
837      method = self.data.capability_delegation.query_mut(query.clone());
838    }
839
840    if method.is_none() {
841      method = self.data.capability_invocation.query_mut(query.clone());
842    }
843
844    match method {
845      Some(MethodRef::Embed(method)) => Some(method),
846      Some(MethodRef::Refer(did)) => self.data.verification_method.query_mut(&did.to_string()),
847      None => self.data.verification_method.query_mut(query),
848    }
849  }
850
851  /// Update the DID components of the document's `id`, controllers, methods and services by applying the provided
852  /// fallible maps.
853  ///
854  /// This is an advanced method that can be useful for DID methods that do not know the document's identifier prior
855  /// to publishing, but should preferably be avoided otherwise.
856  ///
857  /// # Errors
858  /// Any error is returned if any of the functions fail or the updates cause scoped method references to embedded
859  /// methods, or methods and services with identical identifiers in the document. In the case where illegal identifiers
860  /// are detected the supplied the `error_cast` function gets called in order to convert [`Error`] to `E`.
861  pub fn try_map<F, G, H, L, M, E>(
862    self,
863    id_update: F,
864    controller_update: G,
865    methods_update: H,
866    service_update: L,
867    error_cast: M,
868  ) -> Result<Self, E>
869  where
870    F: FnOnce(CoreDID) -> std::result::Result<CoreDID, E>,
871    G: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
872    H: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
873    L: FnMut(CoreDID) -> std::result::Result<CoreDID, E>,
874    M: FnOnce(crate::Error) -> E,
875  {
876    let data = self
877      .data
878      .try_map(id_update, controller_update, methods_update, service_update)?;
879    CoreDocument::try_from(data).map_err(error_cast)
880  }
881
882  /// Unchecked version of [Self::try_map](Self::try_map()).
883  pub fn map_unchecked<F, G, H, L>(
884    self,
885    id_update: F,
886    mut controller_update: G,
887    mut methods_update: H,
888    mut service_update: L,
889  ) -> Self
890  where
891    F: FnOnce(CoreDID) -> CoreDID,
892    G: FnMut(CoreDID) -> CoreDID,
893    H: FnMut(CoreDID) -> CoreDID,
894    L: FnMut(CoreDID) -> CoreDID,
895  {
896    type InfallibleCoreDIDResult = std::result::Result<CoreDID, Infallible>;
897
898    let id_map = |did: CoreDID| -> InfallibleCoreDIDResult { Ok(id_update(did)) };
899    let controller_map = |did: CoreDID| -> InfallibleCoreDIDResult { Ok(controller_update(did)) };
900    let method_map = |did: CoreDID| -> InfallibleCoreDIDResult { Ok(methods_update(did)) };
901    let services_map = |did: CoreDID| -> InfallibleCoreDIDResult { Ok(service_update(did)) };
902    let data = self
903      .data
904      .try_map(id_map, controller_map, method_map, services_map)
905      .expect("unwrapping infallible should be fine");
906    CoreDocument { data }
907  }
908}
909
910impl AsRef<CoreDocument> for CoreDocument {
911  fn as_ref(&self) -> &CoreDocument {
912    self
913  }
914}
915
916impl TryFrom<CoreDocumentData> for CoreDocument {
917  type Error = crate::error::Error;
918  fn try_from(value: CoreDocumentData) -> Result<Self, Self::Error> {
919    match value.check_id_constraints() {
920      Ok(_) => Ok(Self { data: value }),
921      Err(err) => Err(err),
922    }
923  }
924}
925
926impl Display for CoreDocument {
927  fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
928    self.fmt_json(f)
929  }
930}
931
932// =============================================================================
933// JWS verification
934// =============================================================================
935impl CoreDocument {
936  /// Decodes and verifies the provided JWS according to the passed [`JwsVerificationOptions`] and
937  /// [`JwsVerifier`].
938  ///
939  /// Regardless of which options are passed the following conditions must be met in order for a verification attempt to
940  /// take place.
941  /// - The JWS must be encoded according to the JWS compact serialization.
942  /// - The `kid` value in the protected header must be an identifier of a verification method in this DID document, or
943  ///   set explicitly in the `options`.
944  //
945  // NOTE: This is tested in `identity_storage` and `identity_credential`.
946  pub fn verify_jws<'jws, T: JwsVerifier>(
947    &self,
948    jws: &'jws str,
949    detached_payload: Option<&'jws [u8]>,
950    signature_verifier: &T,
951    options: &JwsVerificationOptions,
952  ) -> Result<DecodedJws<'jws>> {
953    let validation_item = Decoder::new()
954      .decode_compact_serialization(jws.as_bytes(), detached_payload)
955      .map_err(Error::JwsVerificationError)?;
956
957    let nonce: Option<&str> = options.nonce.as_deref();
958    // Validate the nonce
959    if validation_item.nonce() != nonce {
960      return Err(Error::JwsVerificationError(
961        identity_verification::jose::error::Error::InvalidParam("invalid nonce value"),
962      ));
963    }
964
965    let method_url_query: DIDUrlQuery<'_> = match &options.method_id {
966      Some(method_id) => method_id.into(),
967      None => validation_item
968        .kid()
969        .ok_or(Error::JwsVerificationError(
970          identity_verification::jose::error::Error::InvalidParam("missing kid value"),
971        ))?
972        .into(),
973    };
974
975    let public_key: &Jwk = self
976      .resolve_method(method_url_query, options.method_scope)
977      .ok_or(Error::MethodNotFound)?
978      .data()
979      .try_public_key_jwk()
980      .map_err(Error::InvalidKeyMaterial)?;
981
982    validation_item
983      .verify(signature_verifier, public_key)
984      .map_err(Error::JwsVerificationError)
985  }
986}
987
988impl CoreDocument {
989  /// Creates a [`CoreDocument`] from a did:jwk DID.
990  pub fn expand_did_jwk(did_jwk: DIDJwk) -> Result<Self, Error> {
991    let verification_method = VerificationMethod::try_from(did_jwk.clone()).map_err(Error::InvalidKeyMaterial)?;
992    let verification_method_id = verification_method.id().clone();
993
994    DocumentBuilder::default()
995      .id(did_jwk.into())
996      .verification_method(verification_method)
997      .assertion_method(verification_method_id.clone())
998      .authentication(verification_method_id.clone())
999      .capability_invocation(verification_method_id.clone())
1000      .capability_delegation(verification_method_id.clone())
1001      .build()
1002  }
1003}
1004
1005#[cfg(test)]
1006mod tests {
1007  use identity_core::convert::FromJson;
1008  use identity_core::convert::ToJson;
1009  use identity_did::DID;
1010  use identity_verification::MethodType;
1011
1012  use crate::service::ServiceBuilder;
1013  use identity_verification::MethodBuilder;
1014  use identity_verification::MethodData;
1015
1016  use super::*;
1017
1018  fn controller() -> CoreDID {
1019    "did:example:1234".parse().unwrap()
1020  }
1021
1022  fn method(controller: &CoreDID, fragment: &str) -> VerificationMethod {
1023    VerificationMethod::builder(Default::default())
1024      .id(controller.to_url().join(fragment).unwrap())
1025      .controller(controller.clone())
1026      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
1027      .data(MethodData::new_multibase(fragment.as_bytes()))
1028      .build()
1029      .unwrap()
1030  }
1031
1032  fn document() -> CoreDocument {
1033    let controller: CoreDID = controller();
1034
1035    CoreDocument::builder(Default::default())
1036      .id(controller.clone())
1037      .verification_method(method(&controller, "#key-1"))
1038      .verification_method(method(&controller, "#key-2"))
1039      .verification_method(method(&controller, "#key-3"))
1040      .authentication(method(&controller, "#auth-key"))
1041      .authentication(controller.to_url().join("#key-3").unwrap())
1042      .key_agreement(controller.to_url().join("#key-4").unwrap())
1043      .build()
1044      .unwrap()
1045  }
1046
1047  #[test]
1048  fn test_controller() {
1049    // One controller.
1050    {
1051      let mut document: CoreDocument = document();
1052      let expected: CoreDID = CoreDID::parse("did:example:one1234").unwrap();
1053      *document.controller_mut() = Some(OneOrSet::new_one(expected.clone()));
1054      assert_eq!(document.controller().unwrap().as_slice(), &[expected]);
1055      // Unset.
1056      *document.controller_mut() = None;
1057      assert!(document.controller().is_none());
1058    }
1059
1060    // Many controllers.
1061    {
1062      let mut document: CoreDocument = document();
1063      let expected_controllers: Vec<CoreDID> = vec![
1064        CoreDID::parse("did:example:many1234").unwrap(),
1065        CoreDID::parse("did:example:many4567").unwrap(),
1066        CoreDID::parse("did:example:many8910").unwrap(),
1067      ];
1068      *document.controller_mut() = Some(expected_controllers.clone().try_into().unwrap());
1069      assert_eq!(document.controller().unwrap().as_slice(), &expected_controllers);
1070      // Unset.
1071      *document.controller_mut() = None;
1072      assert!(document.controller().is_none());
1073    }
1074  }
1075
1076  #[rustfmt::skip]
1077  #[test]
1078  fn test_resolve_method() {
1079    let document: CoreDocument = document();
1080
1081    // Resolve methods by fragment.
1082    assert_eq!(document.resolve_method("#key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1083    assert_eq!(document.resolve_method("#key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1084    assert_eq!(document.resolve_method("#key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1085
1086    // Fine to omit the octothorpe.
1087    assert_eq!(document.resolve_method("key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1088    assert_eq!(document.resolve_method("key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1089    assert_eq!(document.resolve_method("key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1090
1091    // Resolve methods by full DID Url id.
1092    assert_eq!(document.resolve_method("did:example:1234#key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1093    assert_eq!(document.resolve_method("did:example:1234#key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1094    assert_eq!(document.resolve_method("did:example:1234#key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1095
1096    // Scope.
1097    assert_eq!(
1098      document.resolve_method("#key-1", Some(MethodScope::VerificationMethod)).unwrap().id().to_string(), "did:example:1234#key-1"
1099    );
1100  }
1101
1102  #[rustfmt::skip]
1103  #[test]
1104  fn test_resolve_method_mut() {
1105    let mut document: CoreDocument = document();
1106
1107    // Resolve methods by fragment.
1108    assert_eq!(document.resolve_method_mut("#key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1109    assert_eq!(document.resolve_method_mut("#key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1110    assert_eq!(document.resolve_method_mut("#key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1111
1112    // Fine to omit the octothorpe.
1113    assert_eq!(document.resolve_method_mut("key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1114    assert_eq!(document.resolve_method_mut("key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1115    assert_eq!(document.resolve_method_mut("key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1116
1117    // Resolve methods by full DID Url id.
1118    assert_eq!(document.resolve_method_mut("did:example:1234#key-1", None).unwrap().id().to_string(), "did:example:1234#key-1");
1119    assert_eq!(document.resolve_method_mut("did:example:1234#key-2", None).unwrap().id().to_string(), "did:example:1234#key-2");
1120    assert_eq!(document.resolve_method_mut("did:example:1234#key-3", None).unwrap().id().to_string(), "did:example:1234#key-3");
1121
1122    // Resolve with scope.
1123    assert_eq!(
1124      document.resolve_method_mut("#key-1", Some(MethodScope::VerificationMethod)).unwrap().id().to_string(), "did:example:1234#key-1"
1125    );
1126  }
1127
1128  #[test]
1129  fn test_resolve_method_fails() {
1130    let document: CoreDocument = document();
1131
1132    // Resolving an existing reference to a missing method returns None.
1133    assert_eq!(document.resolve_method("#key-4", None), None);
1134
1135    // Resolving a plain DID returns None.
1136    assert_eq!(document.resolve_method("did:example:1234", None), None);
1137
1138    // Resolving an empty string returns None.
1139    assert_eq!(document.resolve_method("", None), None);
1140
1141    // Resolve with scope.
1142    assert_eq!(
1143      document.resolve_method("#key-1", Some(MethodScope::key_agreement())),
1144      None
1145    );
1146  }
1147
1148  #[test]
1149  fn test_resolve_method_mut_fails() {
1150    let mut document: CoreDocument = document();
1151
1152    // Resolving an existing reference to a missing method returns None.
1153    assert_eq!(document.resolve_method_mut("#key-4", None), None);
1154
1155    // Resolving a plain DID returns None.
1156    assert_eq!(document.resolve_method_mut("did:example:1234", None), None);
1157
1158    // Resolving an empty string returns None.
1159    assert_eq!(document.resolve_method_mut("", None), None);
1160
1161    // Resolve with scope.
1162    assert_eq!(
1163      document.resolve_method_mut("#key-1", Some(MethodScope::key_agreement())),
1164      None
1165    );
1166  }
1167
1168  #[rustfmt::skip]
1169  #[test]
1170  fn test_methods_index() {
1171    let document: CoreDocument = document();
1172
1173    // Access methods by index.
1174    assert_eq!(document.methods(None).first().unwrap().id().to_string(), "did:example:1234#key-1");
1175    assert_eq!(document.methods(None).get(2).unwrap().id().to_string(), "did:example:1234#key-3");
1176  }
1177
1178  #[test]
1179  fn test_methods_scope() {
1180    let document: CoreDocument = document();
1181
1182    // VerificationMethod
1183    let verification_methods: Vec<&VerificationMethod> = document.methods(Some(MethodScope::VerificationMethod));
1184    assert_eq!(
1185      verification_methods.first().unwrap().id().to_string(),
1186      "did:example:1234#key-1"
1187    );
1188    assert_eq!(
1189      verification_methods.get(1).unwrap().id().to_string(),
1190      "did:example:1234#key-2"
1191    );
1192    assert_eq!(
1193      verification_methods.get(2).unwrap().id().to_string(),
1194      "did:example:1234#key-3"
1195    );
1196    assert_eq!(verification_methods.len(), 3);
1197
1198    // Authentication
1199    let authentication: Vec<&VerificationMethod> = document.methods(Some(MethodScope::authentication()));
1200    assert_eq!(
1201      authentication.first().unwrap().id().to_string(),
1202      "did:example:1234#auth-key"
1203    );
1204    assert_eq!(
1205      authentication.get(1).unwrap().id().to_string(),
1206      "did:example:1234#key-3"
1207    );
1208    assert_eq!(authentication.len(), 2);
1209  }
1210
1211  #[test]
1212  fn test_attach_verification_relationships() {
1213    let mut document: CoreDocument = document();
1214
1215    let fragment = "#attach-test";
1216    let method = method(document.id(), fragment);
1217    document.insert_method(method, MethodScope::VerificationMethod).unwrap();
1218
1219    assert!(document
1220      .attach_method_relationship(
1221        document.id().to_url().join(fragment).unwrap(),
1222        MethodRelationship::CapabilityDelegation,
1223      )
1224      .unwrap());
1225
1226    assert_eq!(document.verification_relationships().count(), 4);
1227
1228    // Adding it a second time is not an error, but returns false (idempotent).
1229    assert!(!document
1230      .attach_method_relationship(
1231        document.id().to_url().join(fragment).unwrap(),
1232        MethodRelationship::CapabilityDelegation,
1233      )
1234      .unwrap());
1235
1236    // len is still 2.
1237    assert_eq!(document.verification_relationships().count(), 4);
1238
1239    // Attempting to attach a relationship to a non-existing method fails.
1240    assert!(document
1241      .attach_method_relationship(
1242        document.id().to_url().join("#doesNotExist").unwrap(),
1243        MethodRelationship::CapabilityDelegation,
1244      )
1245      .is_err());
1246
1247    // Attempt to attach to an embedded method.
1248    assert!(document
1249      .attach_method_relationship(
1250        document.id().to_url().join("#auth-key").unwrap(),
1251        MethodRelationship::CapabilityDelegation,
1252      )
1253      .is_err());
1254  }
1255
1256  #[test]
1257  fn test_detach_verification_relationships() {
1258    let mut document: CoreDocument = document();
1259
1260    let fragment = "#detach-test";
1261    let method = method(document.id(), fragment);
1262    document.insert_method(method, MethodScope::VerificationMethod).unwrap();
1263
1264    assert!(document
1265      .attach_method_relationship(
1266        document.id().to_url().join(fragment).unwrap(),
1267        MethodRelationship::AssertionMethod,
1268      )
1269      .is_ok());
1270
1271    assert!(document
1272      .detach_method_relationship(
1273        document.id().to_url().join(fragment).unwrap(),
1274        MethodRelationship::AssertionMethod,
1275      )
1276      .unwrap());
1277
1278    // len is 1; the relationship was removed.
1279    assert_eq!(document.verification_relationships().count(), 3);
1280
1281    // Removing it a second time is not an error, but returns false (idempotent).
1282    assert!(!document
1283      .detach_method_relationship(
1284        document.id().to_url().join(fragment).unwrap(),
1285        MethodRelationship::AssertionMethod,
1286      )
1287      .unwrap());
1288
1289    // len is still 1.
1290    assert_eq!(document.verification_relationships().count(), 3);
1291
1292    // Attempting to detach a relationship from a non-existing method fails.
1293    assert!(document
1294      .detach_method_relationship(
1295        document.id().to_url().join("#doesNotExist").unwrap(),
1296        MethodRelationship::AssertionMethod,
1297      )
1298      .is_err());
1299  }
1300
1301  #[test]
1302  fn test_method_insert_duplication() {
1303    let mut document: CoreDocument = document();
1304
1305    let fragment = "#duplication-test";
1306    let method1 = method(document.id(), fragment);
1307    assert!(document
1308      .insert_method(method1.clone(), MethodScope::VerificationMethod)
1309      .is_ok());
1310    assert!(document
1311      .insert_method(method1.clone(), MethodScope::VerificationMethod)
1312      .is_err());
1313    assert!(document
1314      .insert_method(method1.clone(), MethodScope::authentication())
1315      .is_err());
1316
1317    let fragment = "#duplication-test-2";
1318    let method2 = method(document.id(), fragment);
1319    assert!(document.insert_method(method2, MethodScope::assertion_method()).is_ok());
1320    assert!(document
1321      .insert_method(method1.clone(), MethodScope::VerificationMethod)
1322      .is_err());
1323    assert!(document
1324      .insert_method(method1, MethodScope::capability_delegation())
1325      .is_err());
1326  }
1327
1328  #[test]
1329  fn test_method_remove_existence() {
1330    let mut document: CoreDocument = document();
1331
1332    let fragment = "#existence-test";
1333    let method1 = method(document.id(), fragment);
1334    assert!(document
1335      .insert_method(method1.clone(), MethodScope::VerificationMethod)
1336      .is_ok());
1337    assert_eq!(method1, document.remove_method(method1.id()).unwrap());
1338    assert!(document.remove_method(method1.id()).is_none());
1339
1340    let fragment = "#existence-test-2";
1341    let method2 = method(document.id(), fragment);
1342    assert!(document.insert_method(method2, MethodScope::assertion_method()).is_ok());
1343    assert!(document.remove_method(method1.id()).is_none());
1344    assert!(document.remove_method(method1.id()).is_none());
1345
1346    let fragment = "#removal-test-3";
1347    let method3 = method(document.id(), fragment);
1348    assert!(document
1349      .insert_method(method3.clone(), MethodScope::VerificationMethod)
1350      .is_ok());
1351    assert!(document
1352      .attach_method_relationship(fragment, MethodRelationship::CapabilityDelegation)
1353      .is_ok());
1354
1355    assert_eq!(method3, document.remove_method(method3.id()).unwrap());
1356
1357    // Ensure *all* references were removed.
1358    assert!(document.capability_delegation().query(method3.id()).is_none());
1359    assert!(document.verification_method().query(method3.id()).is_none());
1360  }
1361
1362  #[test]
1363  fn test_service_updates() {
1364    let mut document = document();
1365    let service_id = document.id().to_url().join("#service-update-test").unwrap();
1366    let service_type = "test";
1367    let service_endpoint = Url::parse("https://example.com").unwrap();
1368
1369    let service: Service = ServiceBuilder::default()
1370      .id(service_id)
1371      .type_(service_type)
1372      .service_endpoint(service_endpoint)
1373      .build()
1374      .unwrap();
1375    // inserting a service with an identifier not present in the document should be Ok.
1376    assert!(document.insert_service(service.clone()).is_ok());
1377    // inserting a service with the same identifier as an already existing service should fail.
1378    let mut service_clone = service.clone();
1379    *service_clone.service_endpoint_mut() = Url::parse("https://other-example.com").unwrap().into();
1380    assert!(document.insert_service(service_clone).is_err());
1381    // removing an existing service should succeed
1382    assert_eq!(service, document.remove_service(service.id()).unwrap());
1383    // it should now be possible to insert the service again
1384    assert!(document.insert_service(service.clone()).is_ok());
1385
1386    // inserting a method with the same identifier as an existing service should fail
1387    let method: VerificationMethod = MethodBuilder::default()
1388      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
1389      .data(MethodData::PublicKeyBase58(
1390        "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J".into(),
1391      ))
1392      .id(service.id().clone())
1393      .controller(document.id().clone())
1394      .build()
1395      .unwrap();
1396
1397    let method_scopes = [
1398      MethodScope::VerificationMethod,
1399      MethodScope::assertion_method(),
1400      MethodScope::authentication(),
1401      MethodScope::key_agreement(),
1402      MethodScope::capability_delegation(),
1403      MethodScope::capability_invocation(),
1404    ];
1405    for scope in method_scopes {
1406      let mut document_clone = document.clone();
1407      assert!(document_clone.insert_method(method.clone(), scope).is_err());
1408      // should succeed after removing the service
1409      assert!(document_clone.remove_service(service.id()).is_some());
1410      assert!(document_clone.insert_method(method.clone(), scope).is_ok());
1411    }
1412
1413    // inserting a service with the same identifier as a method should fail
1414    for scope in method_scopes {
1415      let mut doc_clone = document.clone();
1416      let valid_method_id = document.id().to_url().join("#valid-method-identifier").unwrap();
1417      let mut valid_method = method.clone();
1418      valid_method.set_id(valid_method_id.clone()).unwrap();
1419      // make sure that the method actually gets inserted
1420      assert!(doc_clone.insert_method(valid_method.clone(), scope).is_ok());
1421      let mut service_clone = service.clone();
1422      service_clone.set_id(valid_method_id).unwrap();
1423      assert!(doc_clone.insert_service(service_clone.clone()).is_err());
1424      // but should work after the method has been removed
1425      assert!(doc_clone.remove_method(valid_method.id()).is_some());
1426      assert!(doc_clone.insert_service(service_clone).is_ok());
1427    }
1428
1429    //removing a service that does not exist should fail
1430    assert!(document
1431      .remove_service(&service.id().join("#service-does-not-exist").unwrap())
1432      .is_none());
1433  }
1434
1435  #[test]
1436  fn serialize_deserialize_roundtrip() {
1437    let document: CoreDocument = document();
1438    let doc_json: String = document.to_json().unwrap();
1439    let doc_json_value: serde_json::Value = document.to_json_value().unwrap();
1440    let doc_json_vec: Vec<u8> = document.to_json_vec().unwrap();
1441    assert_eq!(document, CoreDocument::from_json(&doc_json).unwrap());
1442    assert_eq!(document, CoreDocument::from_json_value(doc_json_value).unwrap());
1443
1444    assert_eq!(document, CoreDocument::from_json_slice(&doc_json_vec).unwrap());
1445  }
1446
1447  #[test]
1448  fn deserialize_valid() {
1449    // The verification method types here are really Ed25519VerificationKey2020, changed to be compatible
1450    // with the current version of this library.
1451    const JSON_DOCUMENT: &str = r#"{
1452      "@context": [
1453        "https://www.w3.org/ns/did/v1",
1454        "https://w3id.org/security/suites/ed25519-2020/v1"
1455      ],
1456      "id": "did:example:123",
1457      "authentication": [
1458        {
1459          "id": "did:example:123#z6MkecaLyHuYWkayBDLw5ihndj3T1m6zKTGqau3A51G7RBf3",
1460          "type": "Ed25519VerificationKey2018",
1461          "controller": "did:example:123",
1462          "publicKeyMultibase": "zAKJP3f7BD6W4iWEQ9jwndVTCBq8ua2Utt8EEjJ6Vxsf"
1463        }
1464      ],
1465      "capabilityInvocation": [
1466        {
1467          "id": "did:example:123#z6MkhdmzFu659ZJ4XKj31vtEDmjvsi5yDZG5L7Caz63oP39k",
1468          "type": "Ed25519VerificationKey2018",
1469          "controller": "did:example:123",
1470          "publicKeyMultibase": "z4BWwfeqdp1obQptLLMvPNgBw48p7og1ie6Hf9p5nTpNN"
1471        }
1472      ],
1473      "capabilityDelegation": [
1474        {
1475          "id": "did:example:123#z6Mkw94ByR26zMSkNdCUi6FNRsWnc2DFEeDXyBGJ5KTzSWyi",
1476          "type": "Ed25519VerificationKey2018",
1477          "controller": "did:example:123",
1478          "publicKeyMultibase": "zHgo9PAmfeoxHG8Mn2XHXamxnnSwPpkyBHAMNF3VyXJCL"
1479        }
1480      ],
1481      "assertionMethod": [
1482        {
1483          "id": "did:example:123#z6MkiukuAuQAE8ozxvmahnQGzApvtW7KT5XXKfojjwbdEomY",
1484          "type": "Ed25519VerificationKey2018",
1485          "controller": "did:example:123",
1486          "publicKeyMultibase": "z5TVraf9itbKXrRvt2DSS95Gw4vqU3CHAdetoufdcKazA"
1487        }
1488      ]
1489  }"#;
1490    let doc: std::result::Result<CoreDocument, Box<dyn std::error::Error>> =
1491      CoreDocument::from_json(JSON_DOCUMENT).map_err(Into::into);
1492    // Print debug representation if the test fails.
1493    dbg!(&doc);
1494    assert!(doc.is_ok());
1495  }
1496
1497  #[test]
1498  fn deserialize_duplicate_method_different_scopes() {
1499    const JSON_VERIFICATION_METHOD_KEY_AGREEMENT: &str = r#"{
1500      "id": "did:example:1234",
1501      "verificationMethod": [
1502        {
1503          "id": "did:example:1234#key1",
1504          "controller": "did:example:1234",
1505          "type": "Ed25519VerificationKey2018",
1506          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1507        }
1508      ],
1509      "keyAgreement": [
1510        {
1511          "id": "did:example:1234#key1",
1512          "controller": "did:example:1234",
1513          "type": "X25519KeyAgreementKey2019",
1514          "publicKeyBase58": "FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x"
1515        }
1516      ]
1517    }"#;
1518
1519    const JSON_KEY_AGREEMENT_CAPABILITY_INVOCATION: &str = r#"{
1520      "id": "did:example:1234",
1521      "capabilityInvocation": [
1522        {
1523          "id": "did:example:1234#key1",
1524          "controller": "did:example:1234",
1525          "type": "Ed25519VerificationKey2018",
1526          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1527        }
1528      ],
1529      "keyAgreement": [
1530        {
1531          "id": "did:example:1234#key1",
1532          "controller": "did:example:1234",
1533          "type": "X25519KeyAgreementKey2019",
1534          "publicKeyBase58": "FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x"
1535        }
1536      ]
1537    }"#;
1538
1539    const JSON_ASSERTION_METHOD_CAPABILITY_INVOCATION: &str = r#"{
1540      "id": "did:example:1234",
1541      "assertionMethod": [
1542        {
1543          "id": "did:example:1234#key1",
1544          "controller": "did:example:1234",
1545          "type": "Ed25519VerificationKey2018",
1546          "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
1547        }
1548      ],
1549      "capabilityInvocation": [
1550        {
1551          "id": "did:example:1234#key1",
1552          "controller": "did:example:1234",
1553          "type": "Ed25519VerificationKey2018",
1554          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1555        }
1556      ]
1557    }"#;
1558
1559    const JSON_VERIFICATION_METHOD_AUTHENTICATION: &str = r#"{
1560      "id": "did:example:1234",
1561      "verificationMethod": [
1562        {
1563          "id": "did:example:1234#key1",
1564          "controller": "did:example:1234",
1565          "type": "Ed25519VerificationKey2018",
1566          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1567        }
1568      ],
1569      "authentication": [
1570        {
1571          "id": "did:example:1234#key1",
1572          "controller": "did:example:1234",
1573          "type": "Ed25519VerificationKey2018",
1574          "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
1575        }
1576      ]
1577    }"#;
1578
1579    const JSON_CAPABILITY_DELEGATION_ASSERTION_METHOD: &str = r#"{
1580      "id": "did:example:1234",
1581      "capabilityDelegation": [
1582        {
1583          "id": "did:example:1234#key1",
1584          "controller": "did:example:1234",
1585          "type": "Ed25519VerificationKey2018",
1586          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1587        }
1588      ],
1589      "assertionMethod": [
1590        {
1591          "id": "did:example:1234#key1",
1592          "controller": "did:example:1234",
1593          "type": "Ed25519VerificationKey2018",
1594          "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
1595        }
1596      ]
1597    }"#;
1598
1599    let verifier = |json: &str| {
1600      let result: std::result::Result<CoreDocument, Box<dyn std::error::Error>> =
1601        CoreDocument::from_json(json).map_err(Into::into);
1602      // Print the json if the test fails to aid debugging.
1603      println!("the following non-spec compliant document was deserialized: \n {json}");
1604      assert!(result.is_err());
1605    };
1606
1607    for json in [
1608      JSON_VERIFICATION_METHOD_KEY_AGREEMENT,
1609      JSON_KEY_AGREEMENT_CAPABILITY_INVOCATION,
1610      JSON_ASSERTION_METHOD_CAPABILITY_INVOCATION,
1611      JSON_VERIFICATION_METHOD_AUTHENTICATION,
1612      JSON_CAPABILITY_DELEGATION_ASSERTION_METHOD,
1613    ] {
1614      verifier(json);
1615    }
1616  }
1617
1618  #[test]
1619  fn deserialize_invalid_id_references() {
1620    const JSON_KEY_AGREEMENT_CAPABILITY_INVOCATION: &str = r#"{
1621      "id": "did:example:1234",
1622      "capabilityInvocation": [
1623        "did:example:1234#key1"
1624      ],
1625      "keyAgreement": [
1626        {
1627          "id": "did:example:1234#key1",
1628          "controller": "did:example:1234",
1629          "type": "X25519KeyAgreementKey2019",
1630          "publicKeyBase58": "FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x"
1631        }
1632      ]
1633    }"#;
1634
1635    const JSON_ASSERTION_METHOD_CAPABILITY_INVOCATION: &str = r#"{
1636      "id": "did:example:1234",
1637      "assertionMethod": [
1638        "did:example:1234#key1", 
1639        {
1640          "id": "did:example:1234#key2",
1641          "controller": "did:example:1234",
1642          "type": "Ed25519VerificationKey2018",
1643          "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
1644        }
1645      ],
1646      "capabilityInvocation": [
1647        {
1648          "id": "did:example:1234#key1",
1649          "controller": "did:example:1234",
1650          "type": "Ed25519VerificationKey2018",
1651          "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J"
1652        }
1653      ]
1654    }"#;
1655
1656    const JSON_AUTHENTICATION_KEY_AGREEMENT: &str = r#"{
1657      "id": "did:example:1234",
1658      "keyAgreement": [
1659         "did:example:1234#key1"
1660      ],
1661      "authentication": [
1662        {
1663          "id": "did:example:1234#key1",
1664          "controller": "did:example:1234",
1665          "type": "Ed25519VerificationKey2018",
1666          "publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
1667        }
1668      ]
1669    }"#;
1670
1671    const JSON_CAPABILITY_DELEGATION_ASSERTION_METHOD: &str = r#"{
1672      "id": "did:example:1234",
1673      "capabilityDelegation": [
1674        "did:example:1234#key1"
1675      ],
1676      "assertionMethod": [
1677        {
1678          "id": "did:example:1234#key1",
1679          "controller": "did:example:1234",
1680          "type": "X25519KeyAgreementKey2019",
1681          "publicKeyBase58": "FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x"
1682        }
1683      ]
1684    }"#;
1685
1686    let verifier = |json: &str| {
1687      let result: std::result::Result<CoreDocument, Box<dyn std::error::Error>> =
1688        CoreDocument::from_json(json).map_err(Into::into);
1689      // Print the json if the test fails to aid debugging.
1690      println!("the following non-spec compliant document was deserialized: \n {json}");
1691      assert!(result.is_err());
1692    };
1693
1694    for json in [
1695      JSON_KEY_AGREEMENT_CAPABILITY_INVOCATION,
1696      JSON_ASSERTION_METHOD_CAPABILITY_INVOCATION,
1697      JSON_AUTHENTICATION_KEY_AGREEMENT,
1698      JSON_CAPABILITY_DELEGATION_ASSERTION_METHOD,
1699    ] {
1700      verifier(json);
1701    }
1702  }
1703
1704  #[test]
1705  fn test_did_jwk_expansion() {
1706    let did_jwk = "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9"
1707      .parse::<DIDJwk>()
1708      .unwrap();
1709    let target_doc = serde_json::from_value(serde_json::json!({
1710      "id": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9",
1711      "verificationMethod": [
1712        {
1713          "id": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9#0",
1714          "type": "JsonWebKey2020",
1715          "controller": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9",
1716          "publicKeyJwk": {
1717            "kty":"OKP",
1718            "crv":"X25519",
1719            "use":"enc",
1720            "x":"3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08"
1721          }
1722        }
1723      ],
1724      "assertionMethod": ["did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9#0"],
1725      "authentication": ["did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9#0"],
1726      "capabilityInvocation": ["did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9#0"],
1727      "capabilityDelegation": ["did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ1c2UiOiJlbmMiLCJ4IjoiM3A3YmZYdDl3YlRUVzJIQzdPUTFOei1EUThoYmVHZE5yZngtRkctSUswOCJ9#0"]
1728    })).unwrap();
1729
1730    assert_eq!(CoreDocument::expand_did_jwk(did_jwk).unwrap(), target_doc);
1731  }
1732}