ssi_dids_core/
method_resolver.rs

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
95// #[async_trait]
96impl<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                                        // The IRI is not referring to a verification method.
129                                        Err(VerificationMethodResolutionError::NotAVerificationMethod(
130                                            method.id().to_string(),
131                                        ))
132                                    }
133                                },
134                                Err(e) => {
135                                    // Dereferencing failed for some reason.
136                                    Err(VerificationMethodResolutionError::InternalError(
137                                        e.to_string(),
138                                    ))
139                                }
140                            }
141                            // ResolveVerificationMethod::dereference(&self.resolver, url, options)
142                        }
143                        Err(_) => {
144                            // The IRI is not a valid DID URL.
145                            Err(VerificationMethodResolutionError::InvalidKeyId(
146                                method.id().to_string(),
147                            ))
148                        }
149                    }
150                } else {
151                    // Not a DID scheme.
152                    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}