use core::fmt;
use core::mem;
use core::str::FromStr;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use indexmap::{IndexMap, IndexSet};
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::ser::SerializeMap as _;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use super::{Did, DidUrl, DidUrlReference, Uri};
use crate::jose::{Jwk, OneOrMany};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum DocumentError {
#[error("`@context` must be a string, a map or a non-empty array")]
InvalidContext,
#[error("verification method `{0}` already exists")]
DuplicateVerificationMethod(DidUrl),
#[error("service `{0}` already exists")]
DuplicateService(DidUrl),
#[error("verification method `{0}` not found")]
VerificationMethodNotFound(DidUrl),
#[error("`{url}` does not belong to document `{document}`")]
ForeignDid {
url: DidUrl,
document: Did,
},
#[error("verification method `{id}` is not listed under `{relationship}`")]
NotInRelationship {
id: DidUrl,
relationship: VerificationRelationship,
},
#[error("unknown verification relationship `{0}`")]
UnknownRelationship(String),
#[error("`{0}` is a core property, not an extension property")]
ReservedProperty(String),
}
fn is_none_or_empty<T>(value: &Option<OneOrMany<T>>) -> bool {
value.as_ref().is_none_or(OneOrMany::is_empty)
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(transparent)]
pub struct Context(Value);
impl Context {
pub const DID_V1: &'static str = "https://www.w3.org/ns/did/v1";
pub fn did_v1() -> Self {
Self::uri(Self::DID_V1)
}
pub fn uri(uri: impl Into<String>) -> Self {
Self(Value::String(uri.into()))
}
pub fn uris<I, S>(uris: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
Self(Value::Array(
uris.into_iter().map(|s| Value::String(s.into())).collect(),
))
}
pub fn new(value: Value) -> Result<Self, DocumentError> {
match &value {
Value::String(_) | Value::Object(_) => Ok(Self(value)),
Value::Array(items) if !items.is_empty() => Ok(Self(value)),
_ => Err(DocumentError::InvalidContext),
}
}
pub fn as_value(&self) -> &Value {
&self.0
}
pub fn into_value(self) -> Value {
self.0
}
pub fn contains(&self, uri: &str) -> bool {
match &self.0 {
Value::String(s) => s == uri,
Value::Array(items) => items.iter().any(|item| item.as_str() == Some(uri)),
_ => false,
}
}
}
impl<'de> Deserialize<'de> for Context {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Self::new(Value::deserialize(deserializer)?).map_err(de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum VerificationRelationship {
Authentication,
AssertionMethod,
KeyAgreement,
CapabilityInvocation,
CapabilityDelegation,
}
impl VerificationRelationship {
pub const ALL: &'static [VerificationRelationship] = &[
Self::Authentication,
Self::AssertionMethod,
Self::KeyAgreement,
Self::CapabilityInvocation,
Self::CapabilityDelegation,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::Authentication => "authentication",
Self::AssertionMethod => "assertionMethod",
Self::KeyAgreement => "keyAgreement",
Self::CapabilityInvocation => "capabilityInvocation",
Self::CapabilityDelegation => "capabilityDelegation",
}
}
}
impl fmt::Display for VerificationRelationship {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for VerificationRelationship {
type Err = DocumentError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::ALL
.iter()
.copied()
.find(|rel| rel.as_str() == s)
.ok_or_else(|| DocumentError::UnknownRelationship(s.to_owned()))
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MethodType(Cow<'static, str>);
impl MethodType {
pub const JSON_WEB_KEY_2020: MethodType = MethodType(Cow::Borrowed("JsonWebKey2020"));
pub const JSON_WEB_KEY: MethodType = MethodType(Cow::Borrowed("JsonWebKey"));
pub const MULTIKEY: MethodType = MethodType(Cow::Borrowed("Multikey"));
pub const ED25519_VERIFICATION_KEY_2020: MethodType =
MethodType(Cow::Borrowed("Ed25519VerificationKey2020"));
pub fn new(name: impl Into<String>) -> Self {
Self(Cow::Owned(name.into()))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Debug for MethodType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}
impl fmt::Display for MethodType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl From<&str> for MethodType {
fn from(name: &str) -> Self {
Self::new(name)
}
}
impl From<String> for MethodType {
fn from(name: String) -> Self {
Self::new(name)
}
}
impl PartialEq<str> for MethodType {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for MethodType {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl Serialize for MethodType {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for MethodType {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
String::deserialize(deserializer).map(Self::new)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum VerificationMaterial {
PublicKeyJwk(Box<Jwk>),
PublicKeyMultibase(String),
}
impl VerificationMaterial {
pub fn jwk(jwk: &Jwk) -> Self {
Self::PublicKeyJwk(Box::new(jwk.public()))
}
pub fn multibase(value: impl Into<String>) -> Self {
Self::PublicKeyMultibase(value.into())
}
pub fn as_jwk(&self) -> Option<&Jwk> {
match self {
Self::PublicKeyJwk(jwk) => Some(jwk),
Self::PublicKeyMultibase(_) => None,
}
}
pub fn as_multibase(&self) -> Option<&str> {
match self {
Self::PublicKeyMultibase(value) => Some(value),
Self::PublicKeyJwk(_) => None,
}
}
}
impl Serialize for VerificationMaterial {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
match self {
Self::PublicKeyJwk(jwk) => {
if jwk.is_private() {
return Err(serde::ser::Error::custom(
"`publicKeyJwk` must not contain private parameters",
));
}
map.serialize_entry("publicKeyJwk", jwk)?;
}
Self::PublicKeyMultibase(value) => map.serialize_entry("publicKeyMultibase", value)?,
}
map.end()
}
}
#[derive(Deserialize)]
struct MaterialMembers {
#[serde(rename = "publicKeyJwk", default)]
public_key_jwk: Option<Jwk>,
#[serde(rename = "publicKeyMultibase", default)]
public_key_multibase: Option<String>,
}
impl<'de> Deserialize<'de> for VerificationMaterial {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let members = MaterialMembers::deserialize(deserializer)?;
match (members.public_key_jwk, members.public_key_multibase) {
(Some(jwk), None) if jwk.is_private() => Err(de::Error::custom(
"`publicKeyJwk` must not contain private parameters",
)),
(Some(jwk), None) => Ok(Self::PublicKeyJwk(Box::new(jwk))),
(None, Some(value)) => Ok(Self::PublicKeyMultibase(value)),
(None, None) => Err(de::Error::custom(
"verification method has neither `publicKeyJwk` nor `publicKeyMultibase`",
)),
(Some(_), Some(_)) => Err(de::Error::custom(
"verification method has both `publicKeyJwk` and `publicKeyMultibase`",
)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct VerificationMethod {
pub id: DidUrl,
#[serde(rename = "type")]
pub method_type: MethodType,
pub controller: Did,
#[serde(flatten)]
pub material: VerificationMaterial,
#[serde(flatten)]
pub properties: IndexMap<String, Value>,
}
impl VerificationMethod {
pub fn new(
id: DidUrl,
method_type: MethodType,
controller: Did,
material: VerificationMaterial,
) -> Self {
Self {
id,
method_type,
controller,
material,
properties: IndexMap::new(),
}
}
pub fn public_key_jwk(&self) -> Option<&Jwk> {
self.material.as_jwk()
}
pub fn public_key_multibase(&self) -> Option<&str> {
self.material.as_multibase()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MethodRef {
Reference(DidUrlReference),
Embedded(Box<VerificationMethod>),
}
impl MethodRef {
pub fn reference(id: impl Into<DidUrlReference>) -> Self {
Self::Reference(id.into())
}
pub fn embedded(method: VerificationMethod) -> Self {
Self::Embedded(Box::new(method))
}
pub fn as_embedded(&self) -> Option<&VerificationMethod> {
match self {
Self::Embedded(method) => Some(method),
Self::Reference(_) => None,
}
}
pub fn as_reference(&self) -> Option<&DidUrlReference> {
match self {
Self::Reference(reference) => Some(reference),
Self::Embedded(_) => None,
}
}
pub fn refers_to(&self, id: &DidUrl, base: &Did) -> bool {
match self {
Self::Reference(reference) => reference.refers_to(id, base),
Self::Embedded(method) => method.id == *id,
}
}
}
impl From<DidUrl> for MethodRef {
fn from(id: DidUrl) -> Self {
Self::Reference(id.into())
}
}
impl From<DidUrlReference> for MethodRef {
fn from(reference: DidUrlReference) -> Self {
Self::Reference(reference)
}
}
impl From<VerificationMethod> for MethodRef {
fn from(method: VerificationMethod) -> Self {
Self::embedded(method)
}
}
impl Serialize for MethodRef {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Reference(reference) => reference.serialize(serializer),
Self::Embedded(method) => method.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for MethodRef {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct MethodRefVisitor;
impl<'de> Visitor<'de> for MethodRefVisitor {
type Value = MethodRef;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a DID URL string or a verification method object")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
DidUrlReference::parse(value)
.map(MethodRef::Reference)
.map_err(E::custom)
}
fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
VerificationMethod::deserialize(de::value::MapAccessDeserializer::new(map))
.map(MethodRef::embedded)
}
}
deserializer.deserialize_any(MethodRefVisitor)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(untagged)]
pub enum ServiceEndpoint {
Uri(Uri),
Set(IndexSet<Uri>),
Map(IndexMap<String, Value>),
}
impl ServiceEndpoint {
pub fn uri(uri: Uri) -> Self {
Self::Uri(uri)
}
pub fn uris(&self) -> impl Iterator<Item = &Uri> {
let slice: Box<dyn Iterator<Item = &Uri>> = match self {
Self::Uri(uri) => Box::new(core::iter::once(uri)),
Self::Set(set) => Box::new(set.iter()),
Self::Map(_) => Box::new(core::iter::empty()),
};
slice
}
}
impl From<Uri> for ServiceEndpoint {
fn from(uri: Uri) -> Self {
Self::Uri(uri)
}
}
impl<'de> Deserialize<'de> for ServiceEndpoint {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct EndpointVisitor;
impl<'de> Visitor<'de> for EndpointVisitor {
type Value = ServiceEndpoint;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a URI string, a non-empty array of URI strings, or an object")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Uri::parse(value)
.map(ServiceEndpoint::Uri)
.map_err(E::custom)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut set = IndexSet::new();
while let Some(uri) = seq.next_element::<Uri>()? {
set.insert(uri);
}
if set.is_empty() {
return Err(de::Error::custom(
"`serviceEndpoint` set must contain at least one URI",
));
}
Ok(ServiceEndpoint::Set(set))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut entries = IndexMap::new();
while let Some((key, value)) = map.next_entry::<String, Value>()? {
entries.insert(key, value);
}
Ok(ServiceEndpoint::Map(entries))
}
}
deserializer.deserialize_any(EndpointVisitor)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Service {
pub id: DidUrl,
#[serde(rename = "type")]
pub service_type: OneOrMany<String>,
#[serde(rename = "serviceEndpoint")]
pub service_endpoint: ServiceEndpoint,
#[serde(flatten)]
pub properties: IndexMap<String, Value>,
}
impl Service {
pub fn new(
id: DidUrl,
service_type: impl Into<OneOrMany<String>>,
service_endpoint: impl Into<ServiceEndpoint>,
) -> Self {
Self {
id,
service_type: service_type.into(),
service_endpoint: service_endpoint.into(),
properties: IndexMap::new(),
}
}
pub fn has_type(&self, service_type: &str) -> bool {
self.service_type.iter().any(|t| t == service_type)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(remote = "Self")]
pub struct DidDocument {
#[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")]
pub context: Option<Context>,
pub id: Did,
#[serde(rename = "alsoKnownAs", default, skip_serializing_if = "Vec::is_empty")]
pub also_known_as: Vec<Uri>,
#[serde(default, skip_serializing_if = "is_none_or_empty")]
pub controller: Option<OneOrMany<Did>>,
#[serde(
rename = "verificationMethod",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub verification_method: Vec<VerificationMethod>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub authentication: Vec<MethodRef>,
#[serde(
rename = "assertionMethod",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub assertion_method: Vec<MethodRef>,
#[serde(
rename = "keyAgreement",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub key_agreement: Vec<MethodRef>,
#[serde(
rename = "capabilityInvocation",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub capability_invocation: Vec<MethodRef>,
#[serde(
rename = "capabilityDelegation",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub capability_delegation: Vec<MethodRef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub service: Vec<Service>,
#[serde(flatten)]
pub properties: IndexMap<String, Value>,
}
impl Serialize for DidDocument {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
Self::serialize(self, serializer)
}
}
impl<'de> Deserialize<'de> for DidDocument {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let mut document = Self::deserialize(deserializer)?;
document.check_unique_ids().map_err(de::Error::custom)?;
if is_none_or_empty(&document.controller) {
document.controller = None;
}
Ok(document)
}
}
impl DidDocument {
pub const CORE_PROPERTIES: &'static [&'static str] = &[
"@context",
"id",
"alsoKnownAs",
"controller",
"verificationMethod",
"authentication",
"assertionMethod",
"keyAgreement",
"capabilityInvocation",
"capabilityDelegation",
"service",
];
pub fn new(id: Did) -> Self {
Self {
context: None,
id,
also_known_as: Vec::new(),
controller: None,
verification_method: Vec::new(),
authentication: Vec::new(),
assertion_method: Vec::new(),
key_agreement: Vec::new(),
capability_invocation: Vec::new(),
capability_delegation: Vec::new(),
service: Vec::new(),
properties: IndexMap::new(),
}
}
pub fn builder(id: Did) -> DidDocumentBuilder {
DidDocumentBuilder {
document: Self::new(id),
error: None,
}
}
pub fn relationship(&self, relationship: VerificationRelationship) -> &[MethodRef] {
match relationship {
VerificationRelationship::Authentication => &self.authentication,
VerificationRelationship::AssertionMethod => &self.assertion_method,
VerificationRelationship::KeyAgreement => &self.key_agreement,
VerificationRelationship::CapabilityInvocation => &self.capability_invocation,
VerificationRelationship::CapabilityDelegation => &self.capability_delegation,
}
}
pub fn relationship_mut(
&mut self,
relationship: VerificationRelationship,
) -> &mut Vec<MethodRef> {
match relationship {
VerificationRelationship::Authentication => &mut self.authentication,
VerificationRelationship::AssertionMethod => &mut self.assertion_method,
VerificationRelationship::KeyAgreement => &mut self.key_agreement,
VerificationRelationship::CapabilityInvocation => &mut self.capability_invocation,
VerificationRelationship::CapabilityDelegation => &mut self.capability_delegation,
}
}
fn embedded_methods(&self) -> impl Iterator<Item = &VerificationMethod> {
VerificationRelationship::ALL
.iter()
.flat_map(|rel| self.relationship(*rel))
.filter_map(MethodRef::as_embedded)
}
pub fn verification_method(&self, id: &DidUrl) -> Option<&VerificationMethod> {
self.verification_method
.iter()
.chain(self.embedded_methods())
.find(|method| method.id == *id)
}
pub fn methods(
&self,
relationship: Option<VerificationRelationship>,
) -> impl Iterator<Item = &VerificationMethod> {
let entries: Box<dyn Iterator<Item = &VerificationMethod>> =
match relationship {
None => Box::new(
self.verification_method
.iter()
.chain(self.embedded_methods()),
),
Some(rel) => Box::new(self.relationship(rel).iter().filter_map(
|entry| match entry {
MethodRef::Embedded(method) => Some(&**method),
MethodRef::Reference(reference) => {
let id = reference.resolve(&self.id).ok()?;
self.verification_method.iter().find(|m| m.id == id)
}
},
)),
};
entries
}
pub fn resolve_verification_method(
&self,
id: &DidUrl,
relationship: Option<VerificationRelationship>,
) -> Result<&VerificationMethod, DocumentError> {
if id.did() != &self.id {
return Err(DocumentError::ForeignDid {
url: id.clone(),
document: self.id.clone(),
});
}
let Some(relationship) = relationship else {
return self
.verification_method(id)
.ok_or_else(|| DocumentError::VerificationMethodNotFound(id.clone()));
};
for entry in self.relationship(relationship) {
match entry {
MethodRef::Embedded(method) if method.id == *id => return Ok(method),
MethodRef::Reference(reference) if reference.refers_to(id, &self.id) => {
return self
.verification_method
.iter()
.find(|method| method.id == *id)
.ok_or_else(|| DocumentError::VerificationMethodNotFound(id.clone()));
}
_ => {}
}
}
if self.verification_method(id).is_some() {
Err(DocumentError::NotInRelationship {
id: id.clone(),
relationship,
})
} else {
Err(DocumentError::VerificationMethodNotFound(id.clone()))
}
}
pub fn resolve_method_reference(
&self,
reference: &DidUrlReference,
relationship: Option<VerificationRelationship>,
) -> Result<&VerificationMethod, DocumentError> {
let id = reference.resolve(&self.id).map_err(|_| match reference {
DidUrlReference::Absolute(url) => DocumentError::ForeignDid {
url: url.clone(),
document: self.id.clone(),
},
DidUrlReference::Relative(_) => {
DocumentError::VerificationMethodNotFound(self.id.to_url())
}
})?;
self.resolve_verification_method(&id, relationship)
}
pub fn insert_verification_method(
&mut self,
method: VerificationMethod,
relationships: impl IntoIterator<Item = VerificationRelationship>,
) -> Result<(), DocumentError> {
if self.verification_method(&method.id).is_some() {
return Err(DocumentError::DuplicateVerificationMethod(method.id));
}
let id = method.id.clone();
self.verification_method.push(method);
for relationship in relationships {
self.attach_relationship(&id, relationship)?;
}
Ok(())
}
pub fn check_unique_ids(&self) -> Result<(), DocumentError> {
let mut seen = HashMap::new();
for method in self
.verification_method
.iter()
.chain(self.embedded_methods())
{
if *seen.entry(&method.id).or_insert(method) != method {
return Err(DocumentError::DuplicateVerificationMethod(
method.id.clone(),
));
}
}
let mut seen = HashSet::new();
for service in &self.service {
if !seen.insert(&service.id) {
return Err(DocumentError::DuplicateService(service.id.clone()));
}
}
Ok(())
}
pub fn remove_verification_method(&mut self, id: &DidUrl) -> Option<VerificationMethod> {
let (matching, rest): (Vec<_>, Vec<_>) = mem::take(&mut self.verification_method)
.into_iter()
.partition(|method| method.id == *id);
self.verification_method = rest;
let listed = matching.into_iter().next();
let mut embedded = None;
let base = self.id.clone();
for relationship in VerificationRelationship::ALL {
let entries = self.relationship_mut(*relationship);
let mut index = 0;
while index < entries.len() {
if entries[index].refers_to(id, &base) {
if let MethodRef::Embedded(method) = entries.remove(index) {
embedded.get_or_insert(*method);
}
} else {
index += 1;
}
}
}
listed.or(embedded)
}
pub fn attach_relationship(
&mut self,
id: &DidUrl,
relationship: VerificationRelationship,
) -> Result<bool, DocumentError> {
if !self.verification_method.iter().any(|m| m.id == *id) {
return Err(DocumentError::VerificationMethodNotFound(id.clone()));
}
let base = self.id.clone();
let entries = self.relationship_mut(relationship);
if entries.iter().any(|entry| entry.refers_to(id, &base)) {
return Ok(false);
}
entries.push(MethodRef::Reference(id.clone().into()));
Ok(true)
}
pub fn detach_relationship(
&mut self,
id: &DidUrl,
relationship: VerificationRelationship,
) -> bool {
let base = self.id.clone();
let entries = self.relationship_mut(relationship);
let before = entries.len();
entries.retain(|entry| !entry.refers_to(id, &base));
entries.len() != before
}
pub fn service(&self, id: &DidUrl) -> Option<&Service> {
self.service.iter().find(|service| service.id == *id)
}
pub fn insert_service(&mut self, service: Service) -> Result<(), DocumentError> {
if self.service(&service.id).is_some() {
return Err(DocumentError::DuplicateService(service.id));
}
self.service.push(service);
Ok(())
}
pub fn remove_service(&mut self, id: &DidUrl) -> Option<Service> {
self.service
.iter()
.position(|service| service.id == *id)
.map(|index| self.service.remove(index))
}
pub fn map_dids(&mut self, mut f: impl FnMut(Did) -> Did) {
fn map_url(url: &mut DidUrl, f: &mut impl FnMut(Did) -> Did) {
let did = f(url.did().clone());
if &did != url.did() {
*url = url.with_did(did);
}
}
fn map_method(method: &mut VerificationMethod, f: &mut impl FnMut(Did) -> Did) {
map_url(&mut method.id, f);
method.controller = f(method.controller.clone());
}
self.id = f(self.id.clone());
if let Some(controller) = &mut self.controller {
for did in controller.iter_mut() {
*did = f(did.clone());
}
}
for method in &mut self.verification_method {
map_method(method, &mut f);
}
for relationship in VerificationRelationship::ALL {
for entry in self.relationship_mut(*relationship) {
match entry {
MethodRef::Reference(DidUrlReference::Absolute(url)) => map_url(url, &mut f),
MethodRef::Reference(DidUrlReference::Relative(_)) => {}
MethodRef::Embedded(method) => map_method(method, &mut f),
}
}
}
for service in &mut self.service {
map_url(&mut service.id, &mut f);
}
}
}
#[derive(Debug, Clone)]
pub struct DidDocumentBuilder {
document: DidDocument,
error: Option<DocumentError>,
}
impl DidDocumentBuilder {
#[must_use]
pub fn context(mut self, context: Context) -> Self {
self.document.context = Some(context);
self
}
#[must_use]
pub fn also_known_as(mut self, uri: Uri) -> Self {
self.document.also_known_as.push(uri);
self
}
#[must_use]
pub fn controller(mut self, did: Did) -> Self {
self.document.controller = Some(match self.document.controller.take() {
None => OneOrMany::One(did),
Some(existing) => {
let mut dids = existing.into_vec();
dids.push(did);
OneOrMany::Many(dids)
}
});
self
}
#[must_use]
pub fn verification_method(
mut self,
method: VerificationMethod,
relationships: impl IntoIterator<Item = VerificationRelationship>,
) -> Self {
if self.error.is_none() {
self.error = self
.document
.insert_verification_method(method, relationships)
.err();
}
self
}
#[must_use]
pub fn embedded_method(
mut self,
relationship: VerificationRelationship,
method: VerificationMethod,
) -> Self {
if self.error.is_none() {
if self.document.verification_method(&method.id).is_some() {
self.error = Some(DocumentError::DuplicateVerificationMethod(method.id));
} else {
self.document
.relationship_mut(relationship)
.push(MethodRef::embedded(method));
}
}
self
}
#[must_use]
pub fn service(mut self, service: Service) -> Self {
if self.error.is_none() {
self.error = self.document.insert_service(service).err();
}
self
}
#[must_use]
pub fn property(mut self, name: impl Into<String>, value: impl Into<Value>) -> Self {
let name = name.into();
if DidDocument::CORE_PROPERTIES.contains(&name.as_str()) {
if self.error.is_none() {
self.error = Some(DocumentError::ReservedProperty(name));
}
} else {
self.document.properties.insert(name, value.into());
}
self
}
pub fn build(self) -> Result<DidDocument, DocumentError> {
match self.error {
Some(error) => Err(error),
None => Ok(self.document),
}
}
}