identity_verification/verification_method/
method.rs1use core::fmt::Display;
5use core::fmt::Formatter;
6use std::borrow::Cow;
7
8use identity_did::DIDCompositeJwk;
9use identity_did::DIDJwk;
10use identity_jose::jwk::CompositeJwk;
11use identity_jose::jwk::Jwk;
12use serde::de;
13use serde::Deserialize;
14use serde::Serialize;
15
16use identity_core::common::KeyComparable;
17use identity_core::common::Object;
18use identity_core::convert::FmtJson;
19
20use crate::error::Error;
21use crate::error::Result;
22use crate::verification_method::MethodBuilder;
23use crate::verification_method::MethodData;
24use crate::verification_method::MethodRef;
25use crate::verification_method::MethodType;
26use crate::CustomMethodData;
27use identity_did::CoreDID;
28use identity_did::DIDUrl;
29use identity_did::DID;
30
31#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
35#[serde(from = "_VerificationMethod")]
36pub struct VerificationMethod {
37 pub(crate) id: DIDUrl,
38 pub(crate) controller: CoreDID,
39 #[serde(rename = "type")]
40 pub(crate) type_: MethodType,
41 #[serde(flatten)]
42 pub(crate) data: MethodData,
43 #[serde(flatten)]
44 pub(crate) properties: Object,
45}
46
47fn deserialize_id_with_fragment<'de, D>(deserializer: D) -> Result<DIDUrl, D::Error>
49where
50 D: de::Deserializer<'de>,
51{
52 let did_url: DIDUrl = DIDUrl::deserialize(deserializer)?;
53 if did_url.fragment().unwrap_or_default().is_empty() {
54 return Err(de::Error::custom("method id missing fragment"));
55 }
56 Ok(did_url)
57}
58
59impl VerificationMethod {
60 pub fn builder(properties: Object) -> MethodBuilder {
68 MethodBuilder::new(properties)
69 }
70
71 pub fn from_builder(builder: MethodBuilder) -> Result<Self> {
73 let id: DIDUrl = builder.id.ok_or(Error::InvalidMethod("missing id"))?;
74 if id.fragment().unwrap_or_default().is_empty() {
75 return Err(Error::InvalidMethod("empty id fragment"));
76 }
77
78 if let Some(MethodData::PublicKeyJwk(ref jwk)) = builder.data {
79 if !jwk.is_public() {
80 return Err(crate::error::Error::PrivateKeyMaterialExposed);
81 }
82 };
83
84 Ok(VerificationMethod {
85 id,
86 controller: builder.controller.ok_or(Error::InvalidMethod("missing controller"))?,
87 type_: builder.type_.ok_or(Error::InvalidMethod("missing type"))?,
88 data: builder.data.ok_or(Error::InvalidMethod("missing data"))?,
89 properties: builder.properties,
90 })
91 }
92
93 pub fn id(&self) -> &DIDUrl {
99 &self.id
100 }
101
102 pub fn set_id(&mut self, id: DIDUrl) -> Result<()> {
107 if id.fragment().unwrap_or_default().is_empty() {
108 return Err(Error::MissingIdFragment);
109 }
110 self.id = id;
111 Ok(())
112 }
113
114 pub fn controller(&self) -> &CoreDID {
116 &self.controller
117 }
118
119 pub fn controller_mut(&mut self) -> &mut CoreDID {
121 &mut self.controller
122 }
123
124 pub fn type_(&self) -> &MethodType {
126 &self.type_
127 }
128
129 pub fn type_mut(&mut self) -> &mut MethodType {
131 &mut self.type_
132 }
133
134 pub fn data(&self) -> &MethodData {
136 &self.data
137 }
138
139 pub fn data_mut(&mut self) -> &mut MethodData {
141 &mut self.data
142 }
143
144 pub fn properties(&self) -> &Object {
146 &self.properties
147 }
148
149 pub fn properties_mut(&mut self) -> &mut Object {
151 &mut self.properties
152 }
153
154 pub fn into_method_ref(self) -> MethodRef {
156 MethodRef::Embed(self)
157 }
158
159 pub fn map<F>(self, mut f: F) -> VerificationMethod
163 where
164 F: FnMut(CoreDID) -> CoreDID,
165 {
166 VerificationMethod {
167 id: self.id.map(&mut f),
168 controller: f(self.controller),
169 type_: self.type_,
170 data: self.data,
171 properties: self.properties,
172 }
173 }
174
175 pub fn try_map<F, E>(self, mut f: F) -> Result<VerificationMethod, E>
177 where
178 F: FnMut(CoreDID) -> Result<CoreDID, E>,
179 {
180 Ok(VerificationMethod {
181 id: self.id.try_map(&mut f)?,
182 controller: f(self.controller)?,
183 type_: self.type_,
184 data: self.data,
185 properties: self.properties,
186 })
187 }
188}
189
190impl VerificationMethod {
191 pub fn new_from_jwk<D: DID>(did: D, key: Jwk, fragment: Option<&str>) -> Result<Self> {
206 let fragment: Cow<'_, str> = {
208 let given_fragment: &str = fragment
209 .or_else(|| key.kid())
210 .ok_or(crate::error::Error::InvalidMethod(
211 "an explicit fragment or JWK kid is required",
212 ))?;
213 if given_fragment.starts_with('#') {
215 Cow::Borrowed(given_fragment)
216 } else {
217 Cow::Owned(format!("#{given_fragment}"))
218 }
219 };
220
221 let id: DIDUrl = did.to_url().join(fragment).map_err(Error::DIDUrlConstructionError)?;
222
223 MethodBuilder::default()
224 .id(id)
225 .controller(did.into())
226 .type_(MethodType::JSON_WEB_KEY_2020)
227 .data(MethodData::PublicKeyJwk(key))
228 .build()
229 }
230}
231
232impl VerificationMethod {
233 pub fn new_from_compositejwk<D: DID>(did: D, key: CompositeJwk, fragment: Option<&str>) -> Result<Self> {
240 let composite_fragment = || {
242 let maybe_tpk_kid = key.traditional_public_key().kid();
243 let maybe_pqpk_kid = key.pq_public_key().kid();
244 if let (Some(tpk_kid), Some(pqpk_kid)) = (maybe_tpk_kid, maybe_pqpk_kid) {
245 Some(Cow::Owned(format!("{tpk_kid}~{pqpk_kid}")))
246 } else {
247 maybe_tpk_kid.or(maybe_pqpk_kid).map(Cow::Borrowed)
248 }
249 };
250
251 let fragment = {
252 let given_fragment = fragment
253 .map(Cow::Borrowed)
254 .or_else(composite_fragment)
255 .ok_or(Error::InvalidMethod("an explicit fragment or kid is required"))?;
256
257 if given_fragment.starts_with('#') {
259 given_fragment
260 } else {
261 Cow::Owned(format!("#{given_fragment}"))
262 }
263 };
264
265 let id: DIDUrl = did.to_url().join(fragment).map_err(Error::DIDUrlConstructionError)?;
266
267 MethodBuilder::default()
268 .id(id)
269 .type_(MethodType::custom("CompositeJsonWebKey"))
270 .controller(did.into())
271 .data(MethodData::CompositeJwk(key))
272 .build()
273 }
274}
275
276impl Display for VerificationMethod {
277 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
278 self.fmt_json(f)
279 }
280}
281
282impl AsRef<DIDUrl> for VerificationMethod {
283 fn as_ref(&self) -> &DIDUrl {
284 self.id()
285 }
286}
287
288impl KeyComparable for VerificationMethod {
289 type Key = DIDUrl;
290
291 #[inline]
292 fn key(&self) -> &Self::Key {
293 self.id()
294 }
295}
296
297impl TryFrom<DIDJwk> for VerificationMethod {
298 type Error = Error;
299 fn try_from(did: DIDJwk) -> Result<Self, Self::Error> {
300 let jwk = did.jwk();
301 Self::new_from_jwk(did, jwk, Some("0"))
302 }
303}
304
305impl TryFrom<DIDCompositeJwk> for VerificationMethod {
306 type Error = Error;
307 fn try_from(did: DIDCompositeJwk) -> Result<Self, Self::Error> {
308 let jwk = did.composite_jwk();
309 Self::new_from_compositejwk(did, jwk, Some("0"))
310 }
311}
312
313#[derive(Deserialize)]
317struct _VerificationMethod {
318 #[serde(deserialize_with = "deserialize_id_with_fragment")]
319 pub(crate) id: DIDUrl,
320 pub(crate) controller: CoreDID,
321 #[serde(rename = "type")]
322 pub(crate) type_: MethodType,
323 #[serde(flatten)]
324 pub(crate) data: MethodData,
325 #[serde(flatten)]
326 pub(crate) properties: Object,
327}
328
329impl From<_VerificationMethod> for VerificationMethod {
330 fn from(value: _VerificationMethod) -> Self {
331 let _VerificationMethod {
332 id,
333 controller,
334 type_,
335 data,
336 mut properties,
337 } = value;
338 let key = match &data {
339 MethodData::PublicKeyBase58(_) => "publicKeyBase58",
340 MethodData::PublicKeyJwk(_) => "publicKeyJwk",
341 MethodData::PublicKeyMultibase(_) => "publicKeyMultibase",
342 MethodData::CompositeJwk(_) => "compositeJwk",
343 MethodData::Custom(CustomMethodData { name, .. }) => name.as_str(),
344 };
345 properties.remove(key);
346
347 VerificationMethod {
348 id,
349 controller,
350 type_,
351 data,
352 properties,
353 }
354 }
355}