1use std::{borrow::Cow, marker::PhantomData};
2
3use crate::{document::Document, resolution, DIDResolver, DID, DIDURL};
4use iref::Iri;
5use ssi_claims_core::ProofValidationError;
6use ssi_jwk::{JWKResolver, JWK};
7use ssi_verification_methods_core::{
8 ControllerError, ControllerProvider, GenericVerificationMethod, InvalidVerificationMethod,
9 MaybeJwkVerificationMethod, ProofPurposes, ReferenceOrOwnedRef, VerificationMethod,
10 VerificationMethodResolutionError, VerificationMethodResolver, VerificationMethodSet,
11};
12
13pub struct VerificationMethodDIDResolver<T, M> {
14 resolver: T,
15 options: resolution::Options,
16 method: PhantomData<M>,
17}
18
19impl<T: Default, M> Default for VerificationMethodDIDResolver<T, M> {
20 fn default() -> Self {
21 Self::new(T::default())
22 }
23}
24
25impl<T, M> VerificationMethodDIDResolver<T, M> {
26 pub fn new(resolver: T) -> Self {
27 Self {
28 resolver,
29 options: resolution::Options::default(),
30 method: PhantomData,
31 }
32 }
33
34 pub fn new_with_options(resolver: T, options: resolution::Options) -> Self {
35 Self {
36 resolver,
37 options,
38 method: PhantomData,
39 }
40 }
41
42 pub fn resolver(&self) -> &T {
43 &self.resolver
44 }
45
46 pub fn options(&self) -> &resolution::Options {
47 &self.options
48 }
49}
50
51impl ssi_verification_methods_core::Controller for Document {
52 fn allows_verification_method(&self, id: &iref::Iri, proof_purposes: ProofPurposes) -> bool {
53 DIDURL::new(id.as_bytes()).is_ok_and(|url| {
54 self.verification_relationships
55 .contains(&self.id, url, proof_purposes)
56 })
57 }
58}
59
60impl<T: DIDResolver, M> DIDResolver for VerificationMethodDIDResolver<T, M> {
61 async fn resolve_representation<'a>(
62 &'a self,
63 did: &'a DID,
64 options: resolution::Options,
65 ) -> Result<resolution::Output<Vec<u8>>, resolution::Error> {
66 T::resolve_representation(&self.resolver, did, options).await
67 }
68}
69
70impl<T: DIDResolver, M> ControllerProvider for VerificationMethodDIDResolver<T, M> {
71 type Controller<'a>
72 = Document
73 where
74 Self: 'a;
75
76 async fn get_controller<'a>(
77 &'a self,
78 id: &'a iref::Iri,
79 ) -> Result<Option<Document>, ControllerError> {
80 if id.scheme().as_str() == "did" {
81 match DID::new(id.as_bytes()) {
82 Ok(did) => match self.resolver.resolve_with(did, self.options.clone()).await {
83 Ok(output) => Ok(Some(output.document.into_document())),
84 Err(resolution::Error::NotFound) => Ok(None),
85 Err(e) => Err(ControllerError::InternalError(e.to_string())),
86 },
87 Err(_) => Err(ControllerError::Invalid),
88 }
89 } else {
90 Err(ControllerError::Invalid)
91 }
92 }
93}
94
95impl<T: DIDResolver, M> VerificationMethodResolver for VerificationMethodDIDResolver<T, M>
97where
98 M: VerificationMethod,
99 M: TryFrom<GenericVerificationMethod, Error = InvalidVerificationMethod>,
100{
101 type Method = M;
102
103 async fn resolve_verification_method_with(
104 &self,
105 _issuer: Option<&iref::Iri>,
106 method: Option<ReferenceOrOwnedRef<'_, M>>,
107 options: ssi_verification_methods_core::ResolutionOptions,
108 ) -> Result<Cow<M>, VerificationMethodResolutionError> {
109 let mut deref_options = self.options.clone();
110
111 if let Some(set) = options.accept {
112 if let Some(ty) = set.pick() {
113 deref_options.parameters.public_key_format = Some(ty.to_owned());
114 }
115 }
116
117 match method {
118 Some(method) => {
119 if method.id().scheme().as_str() == "did" {
120 match DIDURL::new(method.id().as_bytes()) {
121 Ok(url) => {
122 match self.resolver.dereference_with(url, deref_options).await {
123 Ok(deref) => match deref.content.into_verification_method() {
124 Ok(any_method) => {
125 Ok(Cow::Owned(M::try_from(any_method.into())?))
126 }
127 Err(_) => {
128 Err(VerificationMethodResolutionError::NotAVerificationMethod(
130 method.id().to_string(),
131 ))
132 }
133 },
134 Err(e) => {
135 Err(VerificationMethodResolutionError::InternalError(
137 e.to_string(),
138 ))
139 }
140 }
141 }
143 Err(_) => {
144 Err(VerificationMethodResolutionError::InvalidKeyId(
146 method.id().to_string(),
147 ))
148 }
149 }
150 } else {
151 Err(VerificationMethodResolutionError::UnsupportedKeyId(
153 method.id().to_string(),
154 ))
155 }
156 }
157 None => Err(VerificationMethodResolutionError::MissingVerificationMethod),
158 }
159 }
160}
161
162impl<T: DIDResolver, M> JWKResolver for VerificationMethodDIDResolver<T, M>
163where
164 M: MaybeJwkVerificationMethod
165 + VerificationMethodSet
166 + TryFrom<GenericVerificationMethod, Error = InvalidVerificationMethod>,
167{
168 async fn fetch_public_jwk(
169 &self,
170 key_id: Option<&str>,
171 ) -> Result<Cow<JWK>, ProofValidationError> {
172 let vm = match key_id {
173 Some(id) => match Iri::new(id) {
174 Ok(iri) => Some(ReferenceOrOwnedRef::Reference(iri)),
175 Err(_) => return Err(ProofValidationError::MissingPublicKey),
176 },
177 None => None,
178 };
179
180 let options = ssi_verification_methods_core::ResolutionOptions {
181 accept: Some(Box::new(M::type_set())),
182 };
183
184 self.resolve_verification_method_with(None, vm, options)
185 .await?
186 .try_to_jwk()
187 .map(Cow::into_owned)
188 .map(Cow::Owned)
189 .ok_or(ProofValidationError::MissingPublicKey)
190 }
191}