identity_verification/verification_method/
builder.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use identity_core::common::Object;
5
6use crate::error::Result;
7use crate::verification_method::MethodData;
8use crate::verification_method::MethodType;
9use crate::verification_method::VerificationMethod;
10use identity_did::CoreDID;
11use identity_did::DIDUrl;
12
13/// A `MethodBuilder` is used to generate a customized `Method`.
14#[derive(Clone, Debug, Default)]
15pub struct MethodBuilder {
16  pub(crate) id: Option<DIDUrl>,
17  pub(crate) controller: Option<CoreDID>,
18  pub(crate) type_: Option<MethodType>,
19  pub(crate) data: Option<MethodData>,
20  pub(crate) properties: Object,
21}
22
23impl MethodBuilder {
24  /// Creates a new `MethodBuilder`.
25  pub fn new(properties: Object) -> Self {
26    Self {
27      id: None,
28      controller: None,
29      type_: None,
30      data: None,
31      properties,
32    }
33  }
34
35  /// Sets the `id` value of the generated `VerificationMethod`.
36  #[must_use]
37  pub fn id(mut self, value: DIDUrl) -> Self {
38    self.id = Some(value);
39    self
40  }
41
42  /// Sets the `controller` value of the generated `VerificationMethod`.
43  #[must_use]
44  pub fn controller(mut self, value: CoreDID) -> Self {
45    self.controller = Some(value);
46    self
47  }
48
49  /// Sets the `type` value of the generated verification `VerificationMethod`.
50  #[must_use]
51  pub fn type_(mut self, value: MethodType) -> Self {
52    self.type_ = Some(value);
53    self
54  }
55
56  /// Sets the `data` value of the generated `VerificationMethod`.
57  #[must_use]
58  pub fn data(mut self, value: MethodData) -> Self {
59    self.data = Some(value);
60    self
61  }
62
63  /// Returns a new `VerificationMethod` based on the `MethodBuilder` configuration.
64  pub fn build(self) -> Result<VerificationMethod> {
65    VerificationMethod::from_builder(self)
66  }
67}
68
69#[cfg(test)]
70mod tests {
71  use identity_core::convert::FromJson;
72  use identity_did::DID;
73  use identity_jose::jwk::Jwk;
74
75  use crate::Error;
76
77  use super::*;
78
79  #[test]
80  fn test_method_builder_success() {
81    for method_data_fn in [MethodData::new_base58, MethodData::new_multibase] {
82      let result: Result<VerificationMethod> = MethodBuilder::default()
83        .id("did:example:123#key".parse().unwrap())
84        .controller("did:example:123".parse().unwrap())
85        .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
86        .data(method_data_fn(""))
87        .build();
88      assert!(result.is_ok());
89    }
90  }
91
92  #[test]
93  fn test_missing_id_fragment() {
94    let result: Result<VerificationMethod> = MethodBuilder::default()
95      .id("did:example:123".parse().unwrap())
96      .controller("did:example:123".parse().unwrap())
97      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
98      .data(MethodData::PublicKeyMultibase("".into()))
99      .build();
100    assert!(matches!(result.unwrap_err(), Error::InvalidMethod(_)));
101  }
102
103  #[test]
104  fn test_missing_id() {
105    let result: Result<VerificationMethod> = MethodBuilder::default()
106      .controller("did:example:123".parse().unwrap())
107      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
108      .data(MethodData::PublicKeyMultibase("".into()))
109      .build();
110    assert!(matches!(result.unwrap_err(), Error::InvalidMethod(_)));
111  }
112
113  #[test]
114  fn test_missing_type() {
115    let result: Result<VerificationMethod> = MethodBuilder::default()
116      .id("did:example:123#key".parse().unwrap())
117      .controller("did:example:123".parse().unwrap())
118      .data(MethodData::PublicKeyMultibase("".into()))
119      .build();
120    assert!(matches!(result.unwrap_err(), Error::InvalidMethod(_)));
121  }
122
123  #[test]
124  fn test_missing_data() {
125    let result: Result<VerificationMethod> = MethodBuilder::default()
126      .id("did:example:123#key".parse().unwrap())
127      .controller("did:example:123".parse().unwrap())
128      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
129      .build();
130    assert!(matches!(result.unwrap_err(), Error::InvalidMethod(_)));
131  }
132
133  #[test]
134  fn test_missing_controller() {
135    let result: Result<VerificationMethod> = MethodBuilder::default()
136      .id("did:example:123#key".parse().unwrap())
137      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
138      .data(MethodData::PublicKeyMultibase("".into()))
139      .build();
140    assert!(matches!(result.unwrap_err(), Error::InvalidMethod(_)));
141  }
142
143  #[test]
144  fn test_jwk_contains_private_key_material() {
145    let jwk: Jwk = Jwk::from_json(
146      r#"
147      {
148        "kty": "OKP",
149        "crv": "Ed25519",
150        "d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
151        "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
152      }
153    "#,
154    )
155    .unwrap();
156
157    let did: CoreDID = "did:example:123".parse().unwrap();
158    let result: Result<VerificationMethod> = MethodBuilder::default()
159      .id(did.clone().join("#key-0").unwrap())
160      .controller(did.clone())
161      .type_(MethodType::ED25519_VERIFICATION_KEY_2018)
162      .data(MethodData::PublicKeyJwk(jwk.clone()))
163      .build();
164    assert!(matches!(result.unwrap_err(), Error::PrivateKeyMaterialExposed));
165
166    let err: Error = VerificationMethod::new_from_jwk(did, jwk, Some("#frag")).unwrap_err();
167    assert!(matches!(err, Error::PrivateKeyMaterialExposed));
168  }
169}