use jose_jwk::Jwk;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, skip_serializing_none};
use smol_str::SmolStr;
use crate::{
did::Did,
did_url::{DidUrl, RelativeDidUrl},
};
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[serde_as]
pub struct Document {
pub id: Did,
pub also_known_as: Option<Vec<String>>,
#[serde_as(as = "Option<OneOrMany<_>>")]
pub controller: Option<Vec<Did>>,
pub verification_method: Option<Vec<VerificationMethodMap>>,
pub authentication: Option<Vec<VerificationMethod>>,
pub assertion_method: Option<Vec<VerificationMethod>>,
pub key_agreement: Option<Vec<VerificationMethod>>,
pub capability_invocation: Option<Vec<VerificationMethod>>,
pub capability_delegation: Option<Vec<VerificationMethod>>,
pub service: Option<Vec<ServiceEndpoint>>,
}
impl Document {
#[must_use]
pub fn resolve_verification_method_url(
&self,
url: &DidUrl,
role: VerificationRole,
) -> Option<VerificationMethodMap> {
let methods = match role {
VerificationRole::Assertion => self.assertion_method.as_deref(),
VerificationRole::Authentication => self.authentication.as_deref(),
VerificationRole::CapabilityDelegation => self.capability_delegation.as_deref(),
VerificationRole::CapabilityInvocation => self.capability_invocation.as_deref(),
VerificationRole::KeyAgreement => self.key_agreement.as_deref(),
}
.unwrap_or_default();
for method in methods {
if let Some(resolved) = self.resolve_verification_method(method)
&& resolved.id == *url
{
return Some(resolved);
}
}
None
}
#[must_use]
pub fn resolve_verification_method(
&self,
method: &VerificationMethod,
) -> Option<VerificationMethodMap> {
match method {
VerificationMethod::Map(map) => Some(*map.clone()),
VerificationMethod::RelativeUrl(relative_url) => {
self.resolve_relative_url(relative_url)
}
VerificationMethod::Url(url) => {
if url.did == self.id
&& let Some(relative_url) = url.to_relative()
{
return self.resolve_relative_url(&relative_url);
}
None
}
}
}
fn resolve_relative_url(&self, url: &RelativeDidUrl) -> Option<VerificationMethodMap> {
for method in self.verification_method.as_deref().unwrap_or_default() {
if method.id.to_relative().as_ref() == Some(url) {
return Some(method.clone());
}
}
None
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum VerificationRole {
Assertion,
Authentication,
CapabilityDelegation,
CapabilityInvocation,
KeyAgreement,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum VerificationMethod {
Map(Box<VerificationMethodMap>),
RelativeUrl(RelativeDidUrl),
Url(DidUrl),
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct VerificationMethodMap {
pub id: DidUrl,
pub controller: Did,
#[serde(rename = "type")]
pub typ: SmolStr,
pub public_key_jwk: Option<Jwk>,
pub public_key_multibase: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde_as]
pub struct ServiceEndpoint {
pub id: String,
#[serde(rename = "type")]
#[serde_as(as = "OneOrMany<_>")]
pub typ: Vec<String>,
}