-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add stubbed didcomm messaging and routing services
Signed-off-by: Daniel Bluhm <[email protected]>
- Loading branch information
Showing
3 changed files
with
151 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,84 @@ | ||
"""DIDComm Messaging implementation using Aries Askar.""" | ||
"""DIDComm Messaging.""" | ||
from dataclasses import dataclass | ||
import json | ||
from typing import Optional | ||
|
||
from pydid.service import DIDCommV2Service | ||
|
||
from didcomm_messaging.crypto import CryptoService, SecretsManager | ||
from didcomm_messaging.packaging import PackagingService | ||
from didcomm_messaging.resolver import DIDResolver | ||
from didcomm_messaging.routing import RoutingService | ||
|
||
|
||
@dataclass | ||
class PackResult: | ||
"""Result of packing a message.""" | ||
|
||
message: bytes | ||
target: str | ||
|
||
|
||
@dataclass | ||
class UnpackResult: | ||
"""Result of unpacking a message.""" | ||
|
||
message: dict | ||
encrytped: bool | ||
authenticated: bool | ||
recipient_kid: str | ||
sender_kid: Optional[str] = None | ||
|
||
|
||
class DIDCommMessaging: | ||
"""Main entrypoint for DIDComm Messaging.""" | ||
|
||
def __init__( | ||
self, | ||
crypto: CryptoService, | ||
secrets: SecretsManager, | ||
resolver: DIDResolver, | ||
packaging: PackagingService, | ||
routing: RoutingService, | ||
): | ||
"""Initialize the DIDComm Messaging service.""" | ||
self.crypto = crypto | ||
self.secrets = secrets | ||
self.resolver = resolver | ||
self.packaging = packaging | ||
self.routing = routing | ||
|
||
def service_to_target(self, service: DIDCommV2Service) -> str: | ||
"""Convert a service to a target uri. | ||
This is a very simple implementation that just returns the first one. | ||
""" | ||
if isinstance(service.service_endpoint, list): | ||
service_endpoint = service.service_endpoint[0] | ||
else: | ||
service_endpoint = service.service_endpoint | ||
|
||
return service_endpoint.uri | ||
|
||
async def pack(self, message: dict, to: str, frm: Optional[str] = None, **options): | ||
"""Pack a message.""" | ||
# TODO crypto layer permits packing to multiple recipients; should we as well? | ||
|
||
encoded_message = await self.packaging.pack( | ||
json.dumps(message).encode(), [to], frm, **options | ||
) | ||
|
||
forward, service = await self.routing.prepare_forward(to, encoded_message) | ||
return PackResult(forward, self.service_to_target(service)) | ||
|
||
async def unpack(self, encoded_message: bytes, **options) -> UnpackResult: | ||
"""Unpack a message.""" | ||
unpacked, metadata = await self.packaging.unpack(encoded_message, **options) | ||
message = json.loads(unpacked.decode()) | ||
return UnpackResult( | ||
message, | ||
encrytped=bool(metadata.method), | ||
authenticated=bool(metadata.sender_kid), | ||
recipient_kid=metadata.recip_key.kid, | ||
sender_kid=metadata.sender_kid, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
"""RoutingService interface.""" | ||
|
||
from typing import Tuple | ||
from pydid.service import DIDCommV2Service | ||
from didcomm_messaging.packaging import PackagingService | ||
from didcomm_messaging.resolver import DIDResolver | ||
|
||
|
||
class RoutingServiceError(Exception): | ||
"""Raised when an error occurs in the RoutingService.""" | ||
|
||
|
||
class RoutingService: | ||
"""RoutingService.""" | ||
|
||
def __init__(self, packaging: PackagingService, resolver: DIDResolver): | ||
"""Initialize the RoutingService.""" | ||
self.packaging = packaging | ||
self.resolver = resolver | ||
|
||
async def _resolve_service(self, to: str) -> DIDCommV2Service: | ||
"""Resolve the service endpoint for a given DID.""" | ||
doc = await self.resolver.resolve_and_parse(to) | ||
if not doc.service: | ||
raise RoutingServiceError(f"No service endpoint found for {to}") | ||
|
||
first_didcomm_service = next( | ||
( | ||
service | ||
for service in doc.service | ||
if isinstance(service, DIDCommV2Service) | ||
), | ||
None, | ||
) | ||
if not first_didcomm_service: | ||
raise RoutingServiceError(f"No DIDCommV2 service endpoint found for {to}") | ||
|
||
return first_didcomm_service | ||
|
||
async def prepare_forward( | ||
self, to: str, encoded_message: bytes | ||
) -> Tuple[bytes, DIDCommV2Service]: | ||
"""Prepare a forward message, if necessary. | ||
Args: | ||
to (str): The recipient of the message. This will be a DID. | ||
encoded_message (bytes): The encoded message. | ||
Returns: | ||
The encoded message, and the service endpoint to forward to. | ||
""" | ||
service = await self._resolve_service(to) | ||
# TODO Do the stuff | ||
return encoded_message, service |