Skip to main content

did_pkarr/doc/
vmethod.rs

1use std::{fmt::Display, str::FromStr};
2
3use fluent_uri::Uri;
4
5use crate::dids::{Did, DidFromUriErr};
6
7/// A verification method most typically is a public key (via `did:key`), or a Did Url
8/// that links to a verification method in a different Did Document.
9#[derive(Debug, Eq, PartialEq, Clone)]
10pub enum VerificationMethod {
11	/// A `did:key`. This does not include the fragment suffix, to save space.
12	DidKey(Did),
13	/// A reference to a verification method in a remote Did Document. Any method other
14	/// than `did:key` can be used.
15	///
16	/// DidUrls allow the use of verification methods that are controlled by third
17	/// parties or with alternative did methods such as did:web. By referencing external
18	/// Dids, users can use more convenient third party services while retaining their
19	/// ability for credible exit.
20	DidUrl(Did),
21}
22
23impl VerificationMethod {
24	pub fn as_did(&self) -> &Did {
25		match self {
26			VerificationMethod::DidKey(did) => did,
27			VerificationMethod::DidUrl(did) => did,
28		}
29	}
30}
31
32#[derive(Debug, thiserror::Error)]
33pub enum ParseVerificationMethodErr {
34	#[error("not a uri")]
35	NotAUri(#[from] fluent_uri::error::ParseError<String>),
36	#[error("did not start with did:")]
37	NotADid(#[from] DidFromUriErr),
38}
39
40impl FromStr for VerificationMethod {
41	type Err = ParseVerificationMethodErr;
42
43	fn from_str(s: &str) -> Result<Self, Self::Err> {
44		let uri: Uri<String> = Uri::try_from(s.to_owned())?;
45		let did = Did::try_from(uri)?;
46		Ok(Self::from(did))
47	}
48}
49
50impl TryFrom<String> for VerificationMethod {
51	type Error = ParseVerificationMethodErr;
52
53	fn try_from(value: String) -> Result<Self, Self::Error> {
54		let uri: Uri<String> = Uri::try_from(value)?;
55		let did = Did::try_from(uri)?;
56
57		Ok(Self::from(did))
58	}
59}
60
61impl From<Did> for VerificationMethod {
62	fn from(value: Did) -> Self {
63		let (prefix, _suffix) = value
64			.as_uri()
65			.path()
66			.split_once(':')
67			.expect("already checked for did: prefix");
68
69		if prefix == "key" {
70			Self::DidKey(value)
71		} else {
72			Self::DidUrl(value)
73		}
74	}
75}
76
77impl<T: AsRef<str>> PartialEq<T> for VerificationMethod {
78	fn eq(&self, other: &T) -> bool {
79		self.as_did() == other
80	}
81}
82
83impl Display for VerificationMethod {
84	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85		write!(f, "{}", self.as_did())
86	}
87}
88
89#[cfg(test)]
90mod tests {
91	use std::str::FromStr as _;
92
93	use crate::dids::test::{DID_KEY_EXAMPLES, DID_WEB_EXAMPLES};
94	use crate::doc::{vmethod::VerificationMethod, Did};
95
96	#[test]
97	fn test_correct_variant() {
98		for e in DID_WEB_EXAMPLES {
99			let did = Did::from_str(e).unwrap();
100			let parsed = VerificationMethod::from_str(e).unwrap();
101			let try_from = VerificationMethod::from(did.clone());
102			assert_eq!(
103				parsed, try_from,
104				"parsing and try_from were not the same for example {e}"
105			);
106			assert_eq!(parsed, VerificationMethod::DidUrl(did));
107		}
108
109		for e in DID_KEY_EXAMPLES {
110			let did = Did::from_str(e).unwrap();
111			let parsed = VerificationMethod::from_str(e).unwrap();
112			let try_from = VerificationMethod::from(did.clone());
113			assert_eq!(
114				parsed, try_from,
115				"parsing and try_from were not the same for example {e}"
116			);
117			assert_eq!(parsed, VerificationMethod::DidKey(did));
118		}
119	}
120
121	#[test]
122	fn test_as_did() {
123		for e in [DID_KEY_EXAMPLES, DID_WEB_EXAMPLES].concat() {
124			let vm = Did::from_str(e).unwrap();
125			assert_eq!(vm.as_uri(), e, "failed example {e}");
126		}
127	}
128}