Skip to content

Commit

Permalink
Merge branch 'feat/didcommv2-proof-of-concept' of github.com:Indicio-…
Browse files Browse the repository at this point in the history
…tech/aries-cloudagent-python into feat/didcommv2-proof-of-concept

Signed-off-by: Colton Wolkins (Indicio work address) <colton@indicio.tech>
  • Loading branch information
TheTechmage committed May 21, 2024
2 parents 4fa84ad + 2a3067e commit 258d8fc
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 140 deletions.
31 changes: 17 additions & 14 deletions aries_cloudagent/askar/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@
from weakref import ref

from aries_askar import AskarError, Session, Store
from didcomm_messaging import (
CryptoService,
DIDCommMessaging,
PackagingService,
RoutingService,
SecretsManager,
)
from didcomm_messaging.resolver import DIDResolver as DMPResolver

from ..cache.base import BaseCache
from ..config.injection_context import InjectionContext
Expand Down Expand Up @@ -263,13 +255,24 @@ async def _setup(self):
BaseStorage,
ClassProvider("aries_cloudagent.storage.askar.AskarStorage", ref(self)),
)
injector.bind_provider(
SecretsManager,
ClassProvider(
"aries_cloudagent.didcomm_v2.adapters.SecretsAdapter", ref(self)
),
)

if self.profile.settings.get("experiment.didcomm_v2"):
from didcomm_messaging import (
CryptoService,
DIDCommMessaging,
PackagingService,
RoutingService,
SecretsManager,
)
from didcomm_messaging.resolver import DIDResolver as DMPResolver

injector.bind_provider(
SecretsManager,
ClassProvider(
"aries_cloudagent.didcomm_v2.adapters.SecretsAdapter", ref(self)
),
)

injector.bind_provider(
DIDCommMessaging,
ClassProvider(
Expand Down
22 changes: 11 additions & 11 deletions aries_cloudagent/config/default_context.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
"""Classes for configuring the default injection context."""

from didcomm_messaging import (
CryptoService,
PackagingService,
RoutingService,
)
from didcomm_messaging.crypto.backend.askar import AskarCryptoService


from ..anoncreds.registry import AnonCredsRegistry
from ..cache.base import BaseCache
from ..cache.in_memory import InMemoryCache
Expand Down Expand Up @@ -73,9 +65,17 @@ async def build_context(self) -> InjectionContext:
)

# DIDComm Messaging
context.injector.bind_instance(CryptoService, AskarCryptoService())
context.injector.bind_instance(PackagingService, PackagingService())
context.injector.bind_instance(RoutingService, RoutingService())
if context.settings.get("experiment.didcomm_v2"):
from didcomm_messaging import (
CryptoService,
PackagingService,
RoutingService,
)
from didcomm_messaging.crypto.backend.askar import AskarCryptoService

context.injector.bind_instance(CryptoService, AskarCryptoService())
context.injector.bind_instance(PackagingService, PackagingService())
context.injector.bind_instance(RoutingService, RoutingService())

await self.bind_providers(context)
await self.load_plugins(context)
Expand Down
3 changes: 0 additions & 3 deletions aries_cloudagent/core/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,7 @@ async def handle_v2_message(
)
if inbound_message.receipt.thread_id:
error_result.message["pthid"] = inbound_message.receipt.thread_id
#error_result.assign_thread_id(inbound_message.receipt.thread_id)
logging.getLogger(__name__).debug("CONSTRUCTED V2 DISPATCHER RESPONSE")
await responder.send_reply(error_result)
logging.getLogger(__name__).debug("LEFT V2 DISPATCHER HANDLER")

async def handle_v1_message(
self,
Expand Down
10 changes: 7 additions & 3 deletions aries_cloudagent/didcomm_v2/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import logging
from typing import Optional, cast
from aries_askar import Key
from didcomm_messaging import SecretsManager
from didcomm_messaging.crypto.backend.askar import AskarSecretKey
from didcomm_messaging.resolver import DIDResolver as DMPResolver

try:
from didcomm_messaging import SecretsManager
from didcomm_messaging.crypto.backend.askar import AskarSecretKey
from didcomm_messaging.resolver import DIDResolver as DMPResolver
except ImportError as err:
raise ImportError("Install the didcommv2 extra to use this module.") from err

from ..core.error import BaseError
from ..core.profile import Profile, ProfileSession
Expand Down
1 change: 0 additions & 1 deletion aries_cloudagent/transport/inbound/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ def process_inbound(self, message: InboundMessage):
async def parse_inbound(self, payload_enc: Union[str, bytes]) -> InboundMessage:
"""Convert a message payload and to an inbound message."""
session = await self.profile.session()
LOGGER.debug("INBOUND SESSION")
payload, receipt = await self.wire_format.parse_message(session, payload_enc)
return InboundMessage(
payload,
Expand Down
121 changes: 13 additions & 108 deletions aries_cloudagent/transport/pack_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
from ..messaging.util import time_now
from ..messaging.base_message import DIDCommVersion
from ..wallet.base import BaseWallet
from ..wallet.error import WalletError, WalletNotFoundError
from ..wallet.error import WalletError
from ..wallet.util import b64_to_str

from .error import WireFormatParseError, WireFormatEncodeError, RecipientKeysError
from .inbound.receipt import MessageReceipt

from .wire_format import BaseWireFormat
from didcomm_messaging import DIDCommMessaging
from didcomm_messaging.crypto.backend.askar import CryptoServiceError

try:
from .v2_pack_format import V2PackWireFormat
except ImportError:
V2PackWireFormat = None

LOGGER = logging.getLogger(__name__)
DIDCOMM_V1_TYP = "JWM/1.0"
Expand Down Expand Up @@ -74,14 +76,20 @@ class PackWireFormat(BaseWireFormat):
def __init__(self):
"""Initialize the pack wire format instance."""
self.v1pack_format = V1PackWireFormat()
self.v2pack_format = V2PackWireFormat()
self.v2pack_format = (
V2PackWireFormat() if V2PackWireFormat is not None else None
)

def get_for_packed_msg(self, packed_msg: Union[str, bytes]) -> BaseWireFormat:
"""Retrieve appropriate DIDComm instance for a given packed message."""
return {
format = {
DIDCommVersion.v1: self.v1pack_format,
DIDCommVersion.v2: self.v2pack_format,
}[get_version_for_packed_msg(packed_msg)]
assert (
format
), "self.v2_pack_format will be set when --experimental-didcomm-v2 is set"
return format

async def parse_message(
self, session: ProfileSession, message_body: Union[str, bytes]
Expand Down Expand Up @@ -326,106 +334,3 @@ def get_recipient_keys(self, message_body: Union[str, bytes]) -> List[str]:
)

return recipient_keys


class V2PackWireFormat(BaseWireFormat):
"""DIDComm V2 message parser and serializer."""

async def parse_message(
self,
session: ProfileSession,
message_body: Union[str, bytes],
) -> Tuple[dict, MessageReceipt]:
"""Parse message."""

messaging = session.inject(DIDCommMessaging)

LOGGER.debug("HIT V2 PACK FORMAT .parse_message()")
LOGGER.debug(message_body)

receipt = MessageReceipt()
receipt.in_time = time_now()
receipt.raw_message = message_body
receipt.didcomm_version = DIDCommVersion.v2

message_dict = None
message_json = message_body

if not message_json:
raise WireFormatParseError("Message body is empty")

try:
message_dict = json.loads(message_json)
except ValueError:
raise WireFormatParseError("Message JSON parsing failed")
if not isinstance(message_dict, dict):
raise WireFormatParseError("Message JSON result is not an object")

wallet = session.inject_or(BaseWallet)
if not wallet:
LOGGER.error("No wallet found")
raise WalletNotFoundError()

# packed messages are detected by the absence of type
if "type" not in message_dict:
try:
message_unpack = await messaging.unpack(message_json)
except CryptoServiceError:
LOGGER.debug("Message unpack failed, falling back to JSON")
else:
# Set message_dict to be the dictionary that we unpacked
message_dict = message_unpack.message

if message_unpack.sender_kid:
receipt.sender_verkey = message_unpack.sender_kid.split("#")[0]
receipt.recipient_verkey = message_unpack.recipient_kid.split("#")[0]
pass

thid = message_dict.get("thid")
receipt.thread_id = thid or message_dict.get("id")

receipt.parent_thread_id = message_dict.get("pthid")

# handle transport decorator
receipt.direct_response_mode = message_dict.get("return_route")

LOGGER.debug("Expanded message: %s", message_dict)

return message_dict, receipt

async def encode_message(
self,
session: ProfileSession,
message_json: Union[str, bytes],
recipient_keys: Sequence[str],
routing_keys: Sequence[str],
sender_key: str,
) -> Union[str, bytes]:
"""Encode an outgoing message for transport.
Args:
session: The profile session for providing wallet access
message_json: The message body to serialize
recipient_keys: A sequence of recipient verkeys
routing_keys: A sequence of routing verkeys
sender_key: The verification key of the sending agent
Returns:
The encoded message
Raises:
MessageEncodeError: If the message could not be encoded
"""
messaging = session.inject(DIDCommMessaging)

if sender_key and recipient_keys:
message = await messaging.pack(
message=message_json,
to=recipient_keys[0],
frm=sender_key,
)
message = message.message
else:
message = message_json
return message
128 changes: 128 additions & 0 deletions aries_cloudagent/transport/v2_pack_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""Standard packed message format class for DIDComm V2."""

import logging

try:
from didcomm_messaging import DIDCommMessaging
from didcomm_messaging.crypto.backend.askar import CryptoServiceError
except ImportError as err:
raise ImportError("Install the didcommv2 extra to use this module.") from err

import json

from typing import Sequence, Tuple, Union

from ..core.profile import ProfileSession


from ..messaging.util import time_now
from ..messaging.base_message import DIDCommVersion
from ..wallet.base import BaseWallet
from ..wallet.error import WalletNotFoundError


from .error import WireFormatParseError
from .inbound.receipt import MessageReceipt

from .wire_format import BaseWireFormat

LOGGER = logging.getLogger(__name__)


class V2PackWireFormat(BaseWireFormat):
"""DIDComm V2 message parser and serializer."""

async def parse_message(
self,
session: ProfileSession,
message_body: Union[str, bytes],
) -> Tuple[dict, MessageReceipt]:
"""Parse message."""

messaging = session.inject(DIDCommMessaging)

receipt = MessageReceipt()
receipt.in_time = time_now()
receipt.raw_message = message_body
receipt.didcomm_version = DIDCommVersion.v2

message_dict = None
message_json = message_body

if not message_json:
raise WireFormatParseError("Message body is empty")

try:
message_dict = json.loads(message_json)
except ValueError:
raise WireFormatParseError("Message JSON parsing failed")
if not isinstance(message_dict, dict):
raise WireFormatParseError("Message JSON result is not an object")

wallet = session.inject_or(BaseWallet)
if not wallet:
LOGGER.error("No wallet found")
raise WalletNotFoundError()

# packed messages are detected by the absence of type
if "type" not in message_dict:
try:
message_unpack = await messaging.unpack(message_json)
except CryptoServiceError:
LOGGER.debug("Message unpack failed, falling back to JSON")
else:
# Set message_dict to be the dictionary that we unpacked
message_dict = message_unpack.message

if message_unpack.sender_kid:
receipt.sender_verkey = message_unpack.sender_kid.split("#")[0]
receipt.recipient_verkey = message_unpack.recipient_kid.split("#")[0]

thid = message_dict.get("thid")
receipt.thread_id = thid or message_dict.get("id")

receipt.parent_thread_id = message_dict.get("pthid")

# handle transport decorator
receipt.direct_response_mode = message_dict.get("return_route")

LOGGER.debug("Expanded message: %s", message_dict)

return message_dict, receipt

async def encode_message(
self,
session: ProfileSession,
message_json: Union[str, bytes],
recipient_keys: Sequence[str],
routing_keys: Sequence[str],
sender_key: str,
) -> Union[str, bytes]:
"""Encode an outgoing message for transport.
Args:
session: The profile session for providing wallet access
message_json: The message body to serialize
recipient_keys: A sequence of recipient verkeys
routing_keys: A sequence of routing verkeys
sender_key: The verification key of the sending agent
Returns:
The encoded message
Raises:
MessageEncodeError: If the message could not be encoded
"""
messaging = session.inject(DIDCommMessaging)

if sender_key and recipient_keys:
message = await messaging.pack(
message=message_json,
to=recipient_keys[0],
frm=sender_key,
)
message = message.message
else:
message = message_json
return message

0 comments on commit 258d8fc

Please sign in to comment.