identity_verification/verification_method/
method.rsuse core::fmt::Display;
use core::fmt::Formatter;
use std::borrow::Cow;
use identity_did::DIDJwk;
use identity_jose::jwk::Jwk;
use serde::de;
use serde::Deserialize;
use serde::Serialize;
use identity_core::common::KeyComparable;
use identity_core::common::Object;
use identity_core::convert::FmtJson;
use crate::error::Error;
use crate::error::Result;
use crate::verification_method::MethodBuilder;
use crate::verification_method::MethodData;
use crate::verification_method::MethodRef;
use crate::verification_method::MethodType;
use crate::CustomMethodData;
use identity_did::CoreDID;
use identity_did::DIDUrl;
use identity_did::DID;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(from = "_VerificationMethod")]
pub struct VerificationMethod {
pub(crate) id: DIDUrl,
pub(crate) controller: CoreDID,
#[serde(rename = "type")]
pub(crate) type_: MethodType,
#[serde(flatten)]
pub(crate) data: MethodData,
#[serde(flatten)]
pub(crate) properties: Object,
}
fn deserialize_id_with_fragment<'de, D>(deserializer: D) -> Result<DIDUrl, D::Error>
where
D: de::Deserializer<'de>,
{
let did_url: DIDUrl = DIDUrl::deserialize(deserializer)?;
if did_url.fragment().unwrap_or_default().is_empty() {
return Err(de::Error::custom("method id missing fragment"));
}
Ok(did_url)
}
impl VerificationMethod {
pub fn builder(properties: Object) -> MethodBuilder {
MethodBuilder::new(properties)
}
pub fn from_builder(builder: MethodBuilder) -> Result<Self> {
let id: DIDUrl = builder.id.ok_or(Error::InvalidMethod("missing id"))?;
if id.fragment().unwrap_or_default().is_empty() {
return Err(Error::InvalidMethod("empty id fragment"));
}
if let Some(MethodData::PublicKeyJwk(ref jwk)) = builder.data {
if !jwk.is_public() {
return Err(crate::error::Error::PrivateKeyMaterialExposed);
}
};
Ok(VerificationMethod {
id,
controller: builder.controller.ok_or(Error::InvalidMethod("missing controller"))?,
type_: builder.type_.ok_or(Error::InvalidMethod("missing type"))?,
data: builder.data.ok_or(Error::InvalidMethod("missing data"))?,
properties: builder.properties,
})
}
pub fn id(&self) -> &DIDUrl {
&self.id
}
pub fn set_id(&mut self, id: DIDUrl) -> Result<()> {
if id.fragment().unwrap_or_default().is_empty() {
return Err(Error::MissingIdFragment);
}
self.id = id;
Ok(())
}
pub fn controller(&self) -> &CoreDID {
&self.controller
}
pub fn controller_mut(&mut self) -> &mut CoreDID {
&mut self.controller
}
pub fn type_(&self) -> &MethodType {
&self.type_
}
pub fn type_mut(&mut self) -> &mut MethodType {
&mut self.type_
}
pub fn data(&self) -> &MethodData {
&self.data
}
pub fn data_mut(&mut self) -> &mut MethodData {
&mut self.data
}
pub fn properties(&self) -> &Object {
&self.properties
}
pub fn properties_mut(&mut self) -> &mut Object {
&mut self.properties
}
pub fn into_method_ref(self) -> MethodRef {
MethodRef::Embed(self)
}
pub fn map<F>(self, mut f: F) -> VerificationMethod
where
F: FnMut(CoreDID) -> CoreDID,
{
VerificationMethod {
id: self.id.map(&mut f),
controller: f(self.controller),
type_: self.type_,
data: self.data,
properties: self.properties,
}
}
pub fn try_map<F, E>(self, mut f: F) -> Result<VerificationMethod, E>
where
F: FnMut(CoreDID) -> Result<CoreDID, E>,
{
Ok(VerificationMethod {
id: self.id.try_map(&mut f)?,
controller: f(self.controller)?,
type_: self.type_,
data: self.data,
properties: self.properties,
})
}
}
impl VerificationMethod {
pub fn new_from_jwk<D: DID>(did: D, key: Jwk, fragment: Option<&str>) -> Result<Self> {
let fragment: Cow<'_, str> = {
let given_fragment: &str = fragment
.or_else(|| key.kid())
.ok_or(crate::error::Error::InvalidMethod(
"an explicit fragment or JWK kid is required",
))?;
if given_fragment.starts_with('#') {
Cow::Borrowed(given_fragment)
} else {
Cow::Owned(format!("#{given_fragment}"))
}
};
let id: DIDUrl = did.to_url().join(fragment).map_err(Error::DIDUrlConstructionError)?;
MethodBuilder::default()
.id(id)
.controller(did.into())
.type_(MethodType::JSON_WEB_KEY_2020)
.data(MethodData::PublicKeyJwk(key))
.build()
}
}
impl Display for VerificationMethod {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.fmt_json(f)
}
}
impl AsRef<DIDUrl> for VerificationMethod {
fn as_ref(&self) -> &DIDUrl {
self.id()
}
}
impl KeyComparable for VerificationMethod {
type Key = DIDUrl;
#[inline]
fn key(&self) -> &Self::Key {
self.id()
}
}
impl TryFrom<DIDJwk> for VerificationMethod {
type Error = Error;
fn try_from(did: DIDJwk) -> Result<Self, Self::Error> {
let jwk = did.jwk();
Self::new_from_jwk(did, jwk, Some("0"))
}
}
#[derive(Deserialize)]
struct _VerificationMethod {
#[serde(deserialize_with = "deserialize_id_with_fragment")]
pub(crate) id: DIDUrl,
pub(crate) controller: CoreDID,
#[serde(rename = "type")]
pub(crate) type_: MethodType,
#[serde(flatten)]
pub(crate) data: MethodData,
#[serde(flatten)]
pub(crate) properties: Object,
}
impl From<_VerificationMethod> for VerificationMethod {
fn from(value: _VerificationMethod) -> Self {
let _VerificationMethod {
id,
controller,
type_,
data,
mut properties,
} = value;
let key = match &data {
MethodData::PublicKeyBase58(_) => "publicKeyBase58",
MethodData::PublicKeyJwk(_) => "publicKeyJwk",
MethodData::PublicKeyMultibase(_) => "publicKeyMultibase",
MethodData::Custom(CustomMethodData { name, .. }) => name.as_str(),
};
properties.remove(key);
VerificationMethod {
id,
controller,
type_,
data,
properties,
}
}
}