identity_verification/verification_method/
method.rs1use core::fmt::Display;
5use core::fmt::Formatter;
6use std::borrow::Cow;
7
8use identity_did::DIDJwk;
9use identity_jose::jwk::Jwk;
10use serde::de;
11use serde::Deserialize;
12use serde::Serialize;
13
14use identity_core::common::KeyComparable;
15use identity_core::common::Object;
16use identity_core::convert::FmtJson;
17
18use crate::error::Error;
19use crate::error::Result;
20use crate::verification_method::MethodBuilder;
21use crate::verification_method::MethodData;
22use crate::verification_method::MethodRef;
23use crate::verification_method::MethodType;
24use crate::CustomMethodData;
25use identity_did::CoreDID;
26use identity_did::DIDUrl;
27use identity_did::DID;
28
29#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
33#[serde(from = "_VerificationMethod")]
34pub struct VerificationMethod {
35 pub(crate) id: DIDUrl,
36 pub(crate) controller: CoreDID,
37 #[serde(rename = "type")]
38 pub(crate) type_: MethodType,
39 #[serde(flatten)]
40 pub(crate) data: MethodData,
41 #[serde(flatten)]
42 pub(crate) properties: Object,
43}
44
45fn deserialize_id_with_fragment<'de, D>(deserializer: D) -> Result<DIDUrl, D::Error>
47where
48 D: de::Deserializer<'de>,
49{
50 let did_url: DIDUrl = DIDUrl::deserialize(deserializer)?;
51 if did_url.fragment().unwrap_or_default().is_empty() {
52 return Err(de::Error::custom("method id missing fragment"));
53 }
54 Ok(did_url)
55}
56
57impl VerificationMethod {
58 pub fn builder(properties: Object) -> MethodBuilder {
66 MethodBuilder::new(properties)
67 }
68
69 pub fn from_builder(builder: MethodBuilder) -> Result<Self> {
71 let id: DIDUrl = builder.id.ok_or(Error::InvalidMethod("missing id"))?;
72 if id.fragment().unwrap_or_default().is_empty() {
73 return Err(Error::InvalidMethod("empty id fragment"));
74 }
75
76 if let Some(MethodData::PublicKeyJwk(ref jwk)) = builder.data {
77 if !jwk.is_public() {
78 return Err(crate::error::Error::PrivateKeyMaterialExposed);
79 }
80 };
81
82 Ok(VerificationMethod {
83 id,
84 controller: builder.controller.ok_or(Error::InvalidMethod("missing controller"))?,
85 type_: builder.type_.ok_or(Error::InvalidMethod("missing type"))?,
86 data: builder.data.ok_or(Error::InvalidMethod("missing data"))?,
87 properties: builder.properties,
88 })
89 }
90
91 pub fn id(&self) -> &DIDUrl {
97 &self.id
98 }
99
100 pub fn set_id(&mut self, id: DIDUrl) -> Result<()> {
105 if id.fragment().unwrap_or_default().is_empty() {
106 return Err(Error::MissingIdFragment);
107 }
108 self.id = id;
109 Ok(())
110 }
111
112 pub fn controller(&self) -> &CoreDID {
114 &self.controller
115 }
116
117 pub fn controller_mut(&mut self) -> &mut CoreDID {
119 &mut self.controller
120 }
121
122 pub fn type_(&self) -> &MethodType {
124 &self.type_
125 }
126
127 pub fn type_mut(&mut self) -> &mut MethodType {
129 &mut self.type_
130 }
131
132 pub fn data(&self) -> &MethodData {
134 &self.data
135 }
136
137 pub fn data_mut(&mut self) -> &mut MethodData {
139 &mut self.data
140 }
141
142 pub fn properties(&self) -> &Object {
144 &self.properties
145 }
146
147 pub fn properties_mut(&mut self) -> &mut Object {
149 &mut self.properties
150 }
151
152 pub fn into_method_ref(self) -> MethodRef {
154 MethodRef::Embed(self)
155 }
156
157 pub fn map<F>(self, mut f: F) -> VerificationMethod
161 where
162 F: FnMut(CoreDID) -> CoreDID,
163 {
164 VerificationMethod {
165 id: self.id.map(&mut f),
166 controller: f(self.controller),
167 type_: self.type_,
168 data: self.data,
169 properties: self.properties,
170 }
171 }
172
173 pub fn try_map<F, E>(self, mut f: F) -> Result<VerificationMethod, E>
175 where
176 F: FnMut(CoreDID) -> Result<CoreDID, E>,
177 {
178 Ok(VerificationMethod {
179 id: self.id.try_map(&mut f)?,
180 controller: f(self.controller)?,
181 type_: self.type_,
182 data: self.data,
183 properties: self.properties,
184 })
185 }
186}
187
188impl VerificationMethod {
189 pub fn new_from_jwk<D: DID>(did: D, key: Jwk, fragment: Option<&str>) -> Result<Self> {
204 let fragment: Cow<'_, str> = {
206 let given_fragment: &str = fragment
207 .or_else(|| key.kid())
208 .ok_or(crate::error::Error::InvalidMethod(
209 "an explicit fragment or JWK kid is required",
210 ))?;
211 if given_fragment.starts_with('#') {
213 Cow::Borrowed(given_fragment)
214 } else {
215 Cow::Owned(format!("#{given_fragment}"))
216 }
217 };
218
219 let id: DIDUrl = did.to_url().join(fragment).map_err(Error::DIDUrlConstructionError)?;
220
221 MethodBuilder::default()
222 .id(id)
223 .controller(did.into())
224 .type_(MethodType::JSON_WEB_KEY_2020)
225 .data(MethodData::PublicKeyJwk(key))
226 .build()
227 }
228}
229
230impl Display for VerificationMethod {
231 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
232 self.fmt_json(f)
233 }
234}
235
236impl AsRef<DIDUrl> for VerificationMethod {
237 fn as_ref(&self) -> &DIDUrl {
238 self.id()
239 }
240}
241
242impl KeyComparable for VerificationMethod {
243 type Key = DIDUrl;
244
245 #[inline]
246 fn key(&self) -> &Self::Key {
247 self.id()
248 }
249}
250
251impl TryFrom<DIDJwk> for VerificationMethod {
252 type Error = Error;
253 fn try_from(did: DIDJwk) -> Result<Self, Self::Error> {
254 let jwk = did.jwk();
255 Self::new_from_jwk(did, jwk, Some("0"))
256 }
257}
258
259#[derive(Deserialize)]
263struct _VerificationMethod {
264 #[serde(deserialize_with = "deserialize_id_with_fragment")]
265 pub(crate) id: DIDUrl,
266 pub(crate) controller: CoreDID,
267 #[serde(rename = "type")]
268 pub(crate) type_: MethodType,
269 #[serde(flatten)]
270 pub(crate) data: MethodData,
271 #[serde(flatten)]
272 pub(crate) properties: Object,
273}
274
275impl From<_VerificationMethod> for VerificationMethod {
276 fn from(value: _VerificationMethod) -> Self {
277 let _VerificationMethod {
278 id,
279 controller,
280 type_,
281 data,
282 mut properties,
283 } = value;
284 let key = match &data {
285 MethodData::PublicKeyBase58(_) => "publicKeyBase58",
286 MethodData::PublicKeyJwk(_) => "publicKeyJwk",
287 MethodData::PublicKeyMultibase(_) => "publicKeyMultibase",
288 MethodData::Custom(CustomMethodData { name, .. }) => name.as_str(),
289 };
290 properties.remove(key);
291
292 VerificationMethod {
293 id,
294 controller,
295 type_,
296 data,
297 properties,
298 }
299 }
300}