11"""Utilities for specifying which verification method is in use for a given DID."""
22
33from abc import ABC , abstractmethod
4- from typing import List , Optional
4+ import logging
5+ from typing import Literal , Optional
56
6- from acapy_agent .core .profile import Profile
7- from acapy_agent .did .did_key import DIDKey
8- from acapy_agent .wallet .key_type import KeyType
7+ from pydid import DIDDocument
8+
9+ from ..core .error import BaseError
10+ from ..core .profile import Profile
11+ from ..did .did_key import DIDKey
12+ from ..resolver .did_resolver import DIDResolver
13+
14+ LOGGER = logging .getLogger (__name__ )
15+
16+
17+ ProofPurposeStr = Literal [
18+ "assertionMethod" ,
19+ "authentication" ,
20+ "capabilityDelegation" ,
21+ "capabilityInvocation" ,
22+ ]
23+ PROOF_PURPOSES = (
24+ "authentication" ,
25+ "assertionMethod" ,
26+ "capabilityInvocation" ,
27+ "capabilityDelegation" ,
28+ )
29+
30+
31+ class VerificationKeyStrategyError (BaseError ):
32+ """Raised on issues with verfication method derivation."""
933
1034
1135class BaseVerificationKeyStrategy (ABC ):
@@ -15,10 +39,11 @@ class BaseVerificationKeyStrategy(ABC):
1539 async def get_verification_method_id_for_did (
1640 self ,
1741 did : str ,
18- profile : Optional [Profile ],
19- allowed_verification_method_types : Optional [List [KeyType ]] = None ,
20- proof_purpose : Optional [str ] = None ,
21- ) -> Optional [str ]:
42+ profile : Profile ,
43+ * ,
44+ proof_type : Optional [str ] = None ,
45+ proof_purpose : Optional [ProofPurposeStr ] = None ,
46+ ) -> str :
2247 """Given a DID, returns the verification key ID in use.
2348
2449 Returns None if no strategy is specified for this DID.
@@ -29,7 +54,7 @@ async def get_verification_method_id_for_did(
2954 :params proof_purpose: the verkey relationship (assertionMethod, keyAgreement, ..)
3055 :returns Optional[str]: the current verkey ID
3156 """
32- pass
57+ ...
3358
3459
3560class DefaultVerificationKeyStrategy (BaseVerificationKeyStrategy ):
@@ -38,13 +63,21 @@ class DefaultVerificationKeyStrategy(BaseVerificationKeyStrategy):
3863 Supports did:key: and did:sov only.
3964 """
4065
66+ def __init__ (self ):
67+ """Initialize the key types mapping."""
68+ self .key_types_mapping = {
69+ "Ed25519Signature2018" : ["Ed25519VerificationKey2018" ],
70+ "Ed25519Signature2020" : ["Ed25519VerificationKey2020" , "Multikey" ],
71+ }
72+
4173 async def get_verification_method_id_for_did (
4274 self ,
4375 did : str ,
44- profile : Optional [Profile ],
45- allowed_verification_method_types : Optional [List [KeyType ]] = None ,
46- proof_purpose : Optional [str ] = None ,
47- ) -> Optional [str ]:
76+ profile : Profile ,
77+ * ,
78+ proof_type : Optional [str ] = None ,
79+ proof_purpose : Optional [ProofPurposeStr ] = None ,
80+ ) -> str :
4881 """Given a did:key or did:sov, returns the verification key ID in use.
4982
5083 Returns None if no strategy is specified for this DID.
@@ -55,10 +88,55 @@ async def get_verification_method_id_for_did(
5588 :params proof_purpose: the verkey relationship (assertionMethod, keyAgreement, ..)
5689 :returns Optional[str]: the current verkey ID
5790 """
91+ proof_type = proof_type or "Ed25519Signature2018"
92+ proof_purpose = proof_purpose or "assertionMethod"
93+
94+ if proof_purpose not in PROOF_PURPOSES :
95+ raise ValueError ("Invalid proof purpose" )
96+
5897 if did .startswith ("did:key:" ):
5998 return DIDKey .from_did (did ).key_id
6099 elif did .startswith ("did:sov:" ):
61100 # key-1 is what uniresolver uses for key id
62101 return did + "#key-1"
63102
64- return None
103+ resolver = profile .inject (DIDResolver )
104+ doc_raw = await resolver .resolve (profile = profile , did = did )
105+ doc = DIDDocument .deserialize (doc_raw )
106+
107+ methods_or_refs = getattr (doc , proof_purpose , [])
108+ # Dereference any refs in the verification relationship
109+ methods = [
110+ await resolver .dereference_verification_method (profile , method , document = doc )
111+ if isinstance (method , str )
112+ else method
113+ for method in methods_or_refs
114+ ]
115+
116+ method_types = self .key_types_mapping .get (proof_type )
117+ if not method_types :
118+ raise VerificationKeyStrategyError (
119+ f"proof type { proof_type } is not supported"
120+ )
121+
122+ # Filter methods by type expected for proof_type
123+ methods = [vm for vm in methods if vm .type in method_types ]
124+ if not methods :
125+ raise VerificationKeyStrategyError (
126+ f"No matching verification method found for did { did } with proof "
127+ f"type { proof_type } and purpose { proof_purpose } "
128+ )
129+
130+ if len (methods ) > 1 :
131+ LOGGER .info (
132+ (
133+ "More than 1 verification method matched for did %s with proof "
134+ "type %s and purpose %s; returning the first: %s"
135+ ),
136+ did ,
137+ proof_type ,
138+ proof_purpose ,
139+ methods [0 ].id ,
140+ )
141+
142+ return methods [0 ].id
0 commit comments