Skip to content

Commit

Permalink
feat: add legacy dmp interface
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Bluhm <[email protected]>
  • Loading branch information
dbluhm committed Jun 4, 2024
1 parent 7031025 commit 9b68316
Show file tree
Hide file tree
Showing 7 changed files with 499 additions and 163 deletions.
176 changes: 13 additions & 163 deletions didcomm_messaging/__init__.py
Original file line number Diff line number Diff line change
@@ -1,170 +1,20 @@
"""DIDComm Messaging."""

from dataclasses import dataclass
import json
from typing import Generic, Optional, List

from pydid.service import DIDCommV2Service

from didcomm_messaging.crypto import CryptoService, SecretsManager, P, S
from didcomm_messaging.crypto import CryptoService, P, S, SecretsManager
from didcomm_messaging.messaging import DIDCommMessaging, DIDCommMessagingService
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_services: List[DIDCommV2Service]

def get_endpoint(self, protocol: str) -> str:
"""Get the first matching endpoint to send the message to."""
return self.get_service(protocol).service_endpoint.uri

def get_service(self, protocol: str) -> DIDCommV2Service:
"""Get the first matching service to send the message to."""
return self.filter_services_by_protocol(protocol)[0]

def filter_services_by_protocol(self, protocol: str) -> List[DIDCommV2Service]:
"""Get all services that start with a specific uri protocol."""
return [
service
for service in self.target_services
if service.service_endpoint.uri.startswith(protocol)
]


@dataclass
class UnpackResult:
"""Result of unpacking a message."""

message: dict
encrytped: bool
authenticated: bool
recipient_kid: str
sender_kid: Optional[str] = None


class DIDCommMessagingService(Generic[P, S]):
"""Main entrypoint for DIDComm Messaging."""

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,
crypto: CryptoService[P, S],
resolver: DIDResolver,
secrets: SecretsManager[S],
packaging: PackagingService[P, S],
routing: RoutingService,
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 packaging.pack(
crypto,
resolver,
secrets,
json.dumps(message).encode(),
[to],
frm,
**options,
)

forward, services = await routing.prepare_forward(
crypto, packaging, resolver, secrets, to, encoded_message
)
return PackResult(forward, services)

async def unpack(
self,
crypto: CryptoService[P, S],
resolver: DIDResolver,
secrets: SecretsManager[S],
packaging: PackagingService[P, S],
encoded_message: bytes,
**options,
) -> UnpackResult:
"""Unpack a message."""
unpacked, metadata = await packaging.unpack(
crypto, resolver, secrets, 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,
)


class DIDCommMessaging(Generic[P, S]):
"""Main entrypoint for DIDComm Messaging."""

def __init__(
self,
crypto: CryptoService[P, S],
secrets: SecretsManager[S],
resolver: DIDResolver,
packaging: PackagingService[P, S],
routing: RoutingService,
):
"""Initialize the DIDComm Messaging service."""
self.crypto = crypto
self.secrets = secrets
self.resolver = resolver
self.packaging = packaging
self.routing = routing
self.dmp = DIDCommMessagingService()

async def pack(
self,
message: dict,
to: str,
frm: Optional[str] = None,
**options,
) -> PackResult:
"""Pack a message."""
return await self.dmp.pack(
self.crypto,
self.resolver,
self.secrets,
self.packaging,
self.routing,
message,
to,
frm,
**options,
)

async def unpack(
self,
encoded_message: bytes,
**options,
) -> UnpackResult:
"""Unpack a message."""
return await self.dmp.unpack(
self.crypto,
self.resolver,
self.secrets,
self.packaging,
encoded_message,
**options,
)
__all__ = [
"CryptoService",
"DIDCommMessaging",
"DIDCommMessagingService",
"DIDResolver",
"P",
"PackagingService",
"RoutingService",
"S",
"SecretsManager",
]
10 changes: 10 additions & 0 deletions didcomm_messaging/legacy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Legacy DIDComm v1 Interfaces.
These components are intended to provide a similar structure to the DIDComm v2
interfaces provided by this library. While the community is transitioning from
DIDComm v1 to v2, having a consistent interface to interact with will help
implementers to support both versions until the transition is complete.
It is expected that a future version of this library will eventually remove
these interfaces.
"""
6 changes: 6 additions & 0 deletions didcomm_messaging/legacy/askar.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional, Sequence, Tuple, cast

from base58 import b58decode
from pydid import VerificationMethod

from didcomm_messaging.crypto.jwe import JweBuilder, JweEnvelope, JweRecipient
from didcomm_messaging.legacy.base import (
Expand All @@ -30,6 +31,11 @@ def kid_to_public_key(self, kid: str) -> AskarKey:
"""
return AskarKey(Key.from_public_bytes(KeyAlg.ED25519, b58decode(kid)), kid)

@classmethod
def verification_method_to_public_key(cls, vm: VerificationMethod) -> AskarKey:
"""Convert a verification method to a public key."""
return AskarKey.from_verification_method(vm)

async def pack_message(
self,
to_verkeys: Sequence[AskarKey],
Expand Down
7 changes: 7 additions & 0 deletions didcomm_messaging/legacy/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from abc import ABC, abstractmethod
from typing import Generic, NamedTuple, Optional, Sequence

from pydid import VerificationMethod
from didcomm_messaging.crypto.base import P, S
from didcomm_messaging.crypto.jwe import JweEnvelope
from didcomm_messaging.multiformats.multibase import Base64UrlEncoder
Expand Down Expand Up @@ -36,6 +38,11 @@ def kid_to_public_key(self, kid: str) -> P:
In DIDComm v1, kids are the base58 encoded keys.
"""

@classmethod
@abstractmethod
def verification_method_to_public_key(cls, vm: VerificationMethod) -> P:
"""Convert a verification method to a public key."""

@abstractmethod
async def pack_message(
self, to_verkeys: Sequence[P], from_key: Optional[S], message: bytes
Expand Down
Loading

0 comments on commit 9b68316

Please sign in to comment.