Skip to content

Commit de4c36b

Browse files
cjhowlandryjones
authored andcommitted
fix: endpoint value cannot be a dict
Signed-off-by: Char Howland <char@indicio.tech>
1 parent ad2148a commit de4c36b

2 files changed

Lines changed: 113 additions & 79 deletions

File tree

aries_cloudagent/resolver/default/indy.py

Lines changed: 78 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
Resolution is performed using the IndyLedger class.
44
"""
55

6-
from typing import Any, Mapping, Pattern
6+
import logging
7+
from typing import Optional, Pattern
78

89
from pydid import DID, DIDDocumentBuilder
910
from pydid.verification_method import Ed25519VerificationKey2018, VerificationMethod
@@ -21,6 +22,8 @@
2122

2223
from ..base import BaseDIDResolver, DIDNotFound, ResolverError, ResolverType
2324

25+
LOGGER = logging.getLogger(__name__)
26+
2427

2528
class NoIndyLedger(ResolverError):
2629
"""Raised when there is no Indy ledger instance configured."""
@@ -46,60 +49,83 @@ def supported_did_regex(self) -> Pattern:
4649
"""Return supported_did_regex of Indy DID Resolver."""
4750
return IndyDID.PATTERN
4851

49-
def _add_endpoint_as_endpoint_value_pair(
50-
self,
51-
builder: DIDDocumentBuilder,
52-
endpoint: str,
53-
recipient_key: VerificationMethod,
54-
):
55-
builder.service.add_didcomm(
56-
ident=self.SERVICE_TYPE_DID_COMMUNICATION,
57-
type_=self.SERVICE_TYPE_DID_COMMUNICATION,
58-
service_endpoint=endpoint,
59-
priority=1,
60-
recipient_keys=[recipient_key],
61-
routing_keys=[],
62-
)
63-
64-
def _add_endpoint_as_map(
52+
def process_endpoint_types(self, types):
53+
"""Process endpoint types to return only expected types,
54+
subset of expected types, or default types.
55+
"""
56+
expected_types = ["endpoint", "did-communication", "DIDComm"]
57+
default_types = ["endpoint", "did-communication"]
58+
if len(types) <= 0:
59+
return default_types
60+
for type in types:
61+
if type not in expected_types:
62+
return default_types
63+
return types
64+
65+
def add_services(
6566
self,
6667
builder: DIDDocumentBuilder,
67-
endpoint: Mapping[str, Any],
68-
recipient_key: VerificationMethod,
68+
endpoints: Optional[dict],
69+
recipient_key: VerificationMethod = None,
6970
):
70-
types = endpoint.get("types", [self.SERVICE_TYPE_DID_COMMUNICATION])
71-
routing_keys = endpoint.get("routingKeys", [])
72-
endpoint_url = endpoint.get("endpoint")
73-
if not endpoint_url:
74-
raise ValueError("endpoint url not found in endpoint attrib")
75-
76-
if self.SERVICE_TYPE_DIDCOMM in types:
77-
builder.service.add(
78-
ident="#didcomm-1",
79-
type_=self.SERVICE_TYPE_DIDCOMM,
80-
service_endpoint=endpoint_url,
81-
recipient_keys=[recipient_key.id],
82-
routing_keys=routing_keys,
83-
accept=["didcomm/v2"],
84-
)
85-
builder.context.append(self.CONTEXT_DIDCOMM_V2)
86-
if self.SERVICE_TYPE_DID_COMMUNICATION in types:
87-
builder.service.add(
88-
ident="did-communication",
89-
type_=self.SERVICE_TYPE_DID_COMMUNICATION,
90-
service_endpoint=endpoint_url,
91-
priority=1,
92-
routing_keys=routing_keys,
93-
recipient_keys=[recipient_key.id],
94-
accept=["didcomm/aip2;env=rfc19"],
95-
)
96-
if self.SERVICE_TYPE_ENDPOINT in types:
97-
builder.service.add(
98-
ident="endpoint",
99-
service_endpoint=endpoint_url,
100-
type_=self.SERVICE_TYPE_ENDPOINT,
71+
"""Add services."""
72+
if not endpoints:
73+
return
74+
75+
endpoint = endpoints.get("endpoint")
76+
routing_keys = endpoints.get("routingKeys", [])
77+
types = endpoints.get("types", [self.SERVICE_TYPE_DID_COMMUNICATION])
78+
79+
other_endpoints = {
80+
key: endpoints[key]
81+
for key in ("profile", "linked_domains")
82+
if key in endpoints
83+
}
84+
85+
if endpoint:
86+
processed_types = self.process_endpoint_types(types)
87+
88+
if self.SERVICE_TYPE_ENDPOINT in processed_types:
89+
builder.service.add(
90+
ident="endpoint",
91+
service_endpoint=endpoint,
92+
type_=self.SERVICE_TYPE_ENDPOINT,
93+
)
94+
95+
if self.SERVICE_TYPE_DID_COMMUNICATION in processed_types:
96+
builder.service.add(
97+
ident="did-communication",
98+
type_=self.SERVICE_TYPE_DID_COMMUNICATION,
99+
service_endpoint=endpoint,
100+
priority=1,
101+
routing_keys=routing_keys,
102+
recipient_keys=[recipient_key.id],
103+
accept=["didcomm/aip2;env=rfc19"],
104+
)
105+
106+
if self.SERVICE_TYPE_DIDCOMM in types:
107+
builder.service.add(
108+
ident="#didcomm-1",
109+
type_=self.SERVICE_TYPE_DIDCOMM,
110+
service_endpoint=endpoint,
111+
recipient_keys=[recipient_key.id],
112+
routing_keys=routing_keys,
113+
accept=["didcomm/v2"],
114+
)
115+
builder.context.append(self.CONTEXT_DIDCOMM_V2)
116+
else:
117+
LOGGER.warning(
118+
"No endpoint for DID although endpoint attrib was resolvable"
101119
)
102120

121+
if other_endpoints:
122+
for type_, endpoint in other_endpoints.items():
123+
builder.service.add(
124+
ident=type_,
125+
type_=EndpointType.get(type_).w3c,
126+
service_endpoint=endpoint,
127+
)
128+
103129
async def _resolve(self, profile: Profile, did: str) -> dict:
104130
"""Resolve an indy DID."""
105131
multitenant_mgr = profile.inject_or(BaseMultitenantManager)
@@ -119,7 +145,7 @@ async def _resolve(self, profile: Profile, did: str) -> dict:
119145
try:
120146
async with ledger:
121147
recipient_key = await ledger.get_key_for_did(did)
122-
endpoints = await ledger.get_all_endpoints_for_did(did)
148+
endpoints: Optional[dict] = await ledger.get_all_endpoints_for_did(did)
123149
except LedgerError as err:
124150
raise DIDNotFound(f"DID {did} could not be resolved") from err
125151

@@ -130,22 +156,7 @@ async def _resolve(self, profile: Profile, did: str) -> dict:
130156
)
131157
builder.authentication.reference(vmethod.id)
132158
builder.assertion_method.reference(vmethod.id)
133-
if endpoints:
134-
for type_, endpoint in endpoints.items():
135-
if type_ == EndpointType.ENDPOINT.indy:
136-
if isinstance(endpoint, dict):
137-
self._add_endpoint_as_map(builder, endpoint, vmethod)
138-
else:
139-
self._add_endpoint_as_endpoint_value_pair(
140-
builder, endpoint, vmethod
141-
)
142-
else:
143-
# Accept all service types for now, i.e. profile, linked_domains
144-
builder.service.add(
145-
ident=type_,
146-
type_=type_,
147-
service_endpoint=endpoint,
148-
)
159+
self.add_services(builder, endpoints, vmethod)
149160

150161
result = builder.build()
151162
return result.serialize()

aries_cloudagent/resolver/default/tests/test_indy.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44

55
from asynctest import mock as async_mock
6+
from pydid.verification_method import VerificationMethod
67

78
from ....core.in_memory import InMemoryProfile
89
from ....core.profile import Profile
@@ -116,11 +117,11 @@ async def test_supports_updated_did_sov_rules(
116117
):
117118
"""Test that new attrib structure is supported."""
118119
example = {
119-
"endpoint": {
120-
"endpoint": "https://example.com/endpoint",
121-
"routingKeys": ["a-routing-key"],
122-
"types": ["DIDComm", "did-communication", "endpoint"],
123-
}
120+
"endpoint": "https://example.com/endpoint",
121+
"routingKeys": ["a-routing-key"],
122+
"types": ["DIDComm", "did-communication", "endpoint"],
123+
"profile": "https://example.com",
124+
"linked_domains": "https://example.com",
124125
}
125126

126127
ledger.get_all_endpoints_for_did = async_mock.CoroutineMock(
@@ -129,19 +130,41 @@ async def test_supports_updated_did_sov_rules(
129130
assert await resolver.resolve(profile, TEST_DID0)
130131

131132
@pytest.mark.asyncio
132-
async def test_supports_updated_did_sov_rules_x_no_endpoint_url(
133+
async def test_supports_updated_did_sov_rules_no_endpoint_url(
133134
self, resolver: IndyDIDResolver, ledger: BaseLedger, profile: Profile
134135
):
135136
"""Test that new attrib structure is supported."""
136137
example = {
137-
"endpoint": {
138-
"routingKeys": ["a-routing-key"],
139-
"types": ["DIDComm", "did-communication", "endpoint"],
140-
}
138+
"routingKeys": ["a-routing-key"],
139+
"types": ["DIDComm", "did-communication", "endpoint"],
141140
}
142141

143142
ledger.get_all_endpoints_for_did = async_mock.CoroutineMock(
144143
return_value=example
145144
)
146-
with pytest.raises(ValueError):
147-
await resolver.resolve(profile, TEST_DID0)
145+
result = await resolver.resolve(profile, TEST_DID0)
146+
assert "service" not in result
147+
148+
@pytest.mark.parametrize(
149+
"types, result",
150+
[
151+
(
152+
[],
153+
["endpoint", "did-communication"],
154+
),
155+
(
156+
["did-communication"],
157+
["did-communication"],
158+
),
159+
(
160+
["endpoint", "did-communication", "DIDComm", "other-endpoint-type"],
161+
["endpoint", "did-communication"],
162+
),
163+
(
164+
["endpoint", "did-communication", "DIDComm"],
165+
["endpoint", "did-communication", "DIDComm"],
166+
),
167+
],
168+
)
169+
def test_process_endpoint_types(self, resolver: IndyDIDResolver, types, result):
170+
assert resolver.process_endpoint_types(types) == result

0 commit comments

Comments
 (0)