identity_document/document/
builder.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use identity_core::common::Object;
5use identity_core::common::Url;
6
7use crate::document::CoreDocument;
8use crate::error::Result;
9use crate::service::Service;
10use identity_did::CoreDID;
11use identity_verification::MethodRef;
12use identity_verification::VerificationMethod;
13
14/// A `DocumentBuilder` is used to generate a customized [`Document`](crate::document::CoreDocument).
15#[derive(Clone, Debug)]
16pub struct DocumentBuilder {
17  pub(crate) id: Option<CoreDID>,
18  pub(crate) controller: Vec<CoreDID>,
19  pub(crate) also_known_as: Vec<Url>,
20  pub(crate) verification_method: Vec<VerificationMethod>,
21  pub(crate) authentication: Vec<MethodRef>,
22  pub(crate) assertion_method: Vec<MethodRef>,
23  pub(crate) key_agreement: Vec<MethodRef>,
24  pub(crate) capability_delegation: Vec<MethodRef>,
25  pub(crate) capability_invocation: Vec<MethodRef>,
26  pub(crate) service: Vec<Service>,
27  pub(crate) properties: Object,
28}
29
30impl DocumentBuilder {
31  /// Creates a new `DocumentBuilder`.
32  pub fn new(properties: Object) -> Self {
33    Self {
34      id: None,
35      controller: Vec::new(),
36      also_known_as: Vec::new(),
37      verification_method: Vec::new(),
38      authentication: Vec::new(),
39      assertion_method: Vec::new(),
40      key_agreement: Vec::new(),
41      capability_delegation: Vec::new(),
42      capability_invocation: Vec::new(),
43      service: Vec::new(),
44      properties,
45    }
46  }
47
48  /// Sets the `id` value.
49  #[must_use]
50  pub fn id(mut self, value: CoreDID) -> Self {
51    self.id = Some(value);
52    self
53  }
54
55  /// Adds a value to the `controller` set.
56  #[must_use]
57  pub fn controller(mut self, value: CoreDID) -> Self {
58    self.controller.push(value);
59    self
60  }
61
62  /// Adds a value to the `alsoKnownAs` set.
63  #[must_use]
64  pub fn also_known_as(mut self, value: Url) -> Self {
65    self.also_known_as.push(value);
66    self
67  }
68
69  /// Adds a value to the `verificationMethod` set.
70  #[must_use]
71  pub fn verification_method(mut self, value: VerificationMethod) -> Self {
72    self.verification_method.push(value);
73    self
74  }
75
76  /// Adds a value to the `authentication` set.
77  #[must_use]
78  pub fn authentication(mut self, value: impl Into<MethodRef>) -> Self {
79    self.authentication.push(value.into());
80    self
81  }
82
83  /// Adds a value to the `assertionMethod` set.
84  #[must_use]
85  pub fn assertion_method(mut self, value: impl Into<MethodRef>) -> Self {
86    self.assertion_method.push(value.into());
87    self
88  }
89
90  /// Adds a value to the `keyAgreement` set.
91  #[must_use]
92  pub fn key_agreement(mut self, value: impl Into<MethodRef>) -> Self {
93    self.key_agreement.push(value.into());
94    self
95  }
96
97  /// Adds a value to the `capabilityDelegation` set.
98  #[must_use]
99  pub fn capability_delegation(mut self, value: impl Into<MethodRef>) -> Self {
100    self.capability_delegation.push(value.into());
101    self
102  }
103
104  /// Adds a value to the `capabilityInvocation` set.
105  #[must_use]
106  pub fn capability_invocation(mut self, value: impl Into<MethodRef>) -> Self {
107    self.capability_invocation.push(value.into());
108    self
109  }
110
111  /// Adds a value to the `service` set.
112  #[must_use]
113  pub fn service(mut self, value: Service) -> Self {
114    self.service.push(value);
115    self
116  }
117
118  /// Returns a new `Document` based on the `DocumentBuilder` configuration.
119  pub fn build(self) -> Result<CoreDocument> {
120    CoreDocument::from_builder(self)
121  }
122}
123
124impl Default for DocumentBuilder {
125  fn default() -> Self {
126    Self::new(Object::default())
127  }
128}
129
130#[cfg(test)]
131mod tests {
132  use super::*;
133  use crate::Error;
134  use identity_did::DID;
135  use identity_verification::MethodData;
136  use identity_verification::MethodType;
137
138  #[test]
139  fn test_missing_id() {
140    let result: Result<CoreDocument> = DocumentBuilder::default().build();
141    assert!(matches!(result.unwrap_err(), Error::InvalidDocument(_, None)));
142  }
143
144  #[test]
145  fn duplicate_id_different_scopes() {
146    let did: CoreDID = "did:example:1234".parse().unwrap();
147    let fragment = "#key1";
148    let id = did.to_url().join(fragment).unwrap();
149
150    let method1: VerificationMethod = VerificationMethod::builder(Default::default())
151      .id(id.clone())
152      .controller(did.clone())
153      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
154      .data(MethodData::PublicKeyBase58(
155        "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J".into(),
156      ))
157      .build()
158      .unwrap();
159
160    let method2: VerificationMethod = VerificationMethod::builder(Default::default())
161      .id(id)
162      .controller(did.clone())
163      .type_(MethodType::X25519_KEY_AGREEMENT_KEY_2019)
164      .data(MethodData::PublicKeyBase58(
165        "FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x".into(),
166      ))
167      .build()
168      .unwrap();
169
170    let result: Result<CoreDocument> = DocumentBuilder::default()
171      .id(did)
172      .verification_method(method1)
173      .key_agreement(method2)
174      .build();
175    assert!(result.is_err());
176  }
177}