Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small AIP-2 updates #1056

Closed
2 changes: 1 addition & 1 deletion aries_cloudagent/commands/tests/test_provision.py
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

class TestProvision(AsyncTestCase):
def test_bad_calls(self):
with self.assertRaises(ArgsParseError):
with self.assertRaises(SystemExit):
test_module.execute([])

with self.assertRaises(SystemExit):
2 changes: 1 addition & 1 deletion aries_cloudagent/commands/tests/test_start.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@

class TestStart(AsyncTestCase):
def test_bad_args(self):
with self.assertRaises(ArgsParseError):
with self.assertRaises(SystemExit):
test_module.execute([])

with self.assertRaises(SystemExit):
34 changes: 12 additions & 22 deletions aries_cloudagent/config/argparse.py
Original file line number Diff line number Diff line change
@@ -78,8 +78,10 @@ def get_settings(args: Namespace):
for group in group_inst:
settings.update(group.get_settings(args))
except ArgsParseError as e:
parser.print_help()
raise e
# this is defined to exit or raise an exception and is
# consistent with an error being raised while the arguments
# are being parsed
parser.error(str(e))
return settings

return get_settings
@@ -651,6 +653,13 @@ class ProtocolGroup(ArgumentGroup):

def add_arguments(self, parser: ArgumentParser):
"""Add protocol-specific command line arguments to the parser."""
parser.add_argument(
"--aip-version",
type=BoundedInt(1, 2),
default=1,
env_var="ACAPY_AIP_VERSION",
help="Set the Aries Interop Profile compatibility version (default 1).",
)
parser.add_argument(
"--auto-ping-connection",
action="store_true",
@@ -725,22 +734,6 @@ def add_arguments(self, parser: ArgumentParser):
env_var="ACAPY_PRESERVE_EXCHANGE_RECORDS",
help="Keep credential exchange records after exchange has completed.",
)
parser.add_argument(
"--emit-new-didcomm-prefix",
action="store_true",
env_var="ACAPY_EMIT_NEW_DIDCOMM_PREFIX",
help="Emit protocol messages with new DIDComm prefix; i.e.,\
'https://didcomm.org/' instead of (default) prefix\
'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/'.",
)
parser.add_argument(
"--emit-new-didcomm-mime-type",
action="store_true",
env_var="ACAPY_EMIT_NEW_DIDCOMM_MIME_TYPE",
help="Send packed agent messages with the DIDComm MIME type\
as of RFC 0044; i.e., 'application/didcomm-envelope-enc'\
instead of 'application/ssi-agent-wire'.",
)
parser.add_argument(
"--exch-use-unencrypted-tags",
action="store_true",
@@ -752,6 +745,7 @@ def add_arguments(self, parser: ArgumentParser):
def get_settings(self, args: Namespace) -> dict:
"""Get protocol settings."""
settings = {}
settings["aip_version"] = args.aip_version
if args.auto_ping_connection:
settings["auto_ping_connection"] = True
if args.invite_base_url:
@@ -796,10 +790,6 @@ def get_settings(self, args: Namespace) -> dict:
raise ArgsParseError("Error writing trace event " + str(e))
if args.preserve_exchange_records:
settings["preserve_exchange_records"] = True
if args.emit_new_didcomm_prefix:
settings["emit_new_didcomm_prefix"] = True
if args.emit_new_didcomm_mime_type:
settings["emit_new_didcomm_mime_type"] = True
if args.exch_use_unencrypted_tags:
settings["exch_use_unencrypted_tags"] = True
environ["EXCH_UNENCRYPTED_TAGS"] = "True"
4 changes: 3 additions & 1 deletion aries_cloudagent/config/wallet.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@

import logging

from typing import Tuple

from ..core.error import ProfileNotFoundError
from ..core.profile import Profile, ProfileManager
from ..wallet.base import BaseWallet, DIDInfo
@@ -17,7 +19,7 @@

async def wallet_config(
context: InjectionContext, provision: bool = False
) -> (Profile, DIDInfo):
) -> Tuple[Profile, DIDInfo]:
"""Initialize the root profile."""

mgr = context.inject(ProfileManager)
7 changes: 6 additions & 1 deletion aries_cloudagent/connections/base_manager.py
Original file line number Diff line number Diff line change
@@ -143,10 +143,15 @@ async def create_did_document(

for (endpoint_index, svc_endpoint) in enumerate(svc_endpoints or []):
endpoint_ident = "indy" if endpoint_index == 0 else f"indy{endpoint_index}"
service_type = (
"did-communication"
if self._session.settings.get("aip_version", 1) >= 2
else "IndyAgent"
)
service = Service(
did_info.did,
endpoint_ident,
"IndyAgent",
service_type,
[pk],
routing_keys,
svc_endpoint,
134 changes: 75 additions & 59 deletions aries_cloudagent/connections/models/diddoc/diddoc.py
Original file line number Diff line number Diff line change
@@ -25,11 +25,16 @@

from .publickey import PublicKey, PublicKeyType
from .service import Service
from .util import canon_did, canon_ref, ok_did, resource
from .util import canon_ref

LOGGER = logging.getLogger(__name__)


def _parseError(msg: str):
LOGGER.debug(msg)
raise ValueError(msg)


class DIDDoc:
"""
DID document, grouping a DID with verification keys and services.
@@ -38,7 +43,8 @@ class DIDDoc:
everything else as URIs (oriented toward W3C-facing operations).
"""

CONTEXT = "https://w3id.org/did/v1"
CONTEXT_V0 = "https://w3id.org/did/v1"
CONTEXT_V1 = "https://www.w3.org/ns/did/v1"

def __init__(self, did: str = None) -> None:
"""
@@ -55,7 +61,7 @@ def __init__(self, did: str = None) -> None:

"""

self._did = canon_did(did) if did else None # allow specification post-hoc
self._did = did
self._pubkey = {}
self._service = {}

@@ -78,7 +84,7 @@ def did(self, value: str) -> None:

"""

self._did = canon_did(value) if value else None
self._did = value

@property
def pubkey(self) -> dict:
@@ -121,29 +127,47 @@ def set(self, item: Union[Service, PublicKey]) -> "DIDDoc":
"Cannot add item {} to DIDDoc on DID {}".format(item, self.did)
)

def serialize(self) -> dict:
def serialize(self, *, version: int = 0) -> dict:
"""
Dump current object to a JSON-compatible dictionary.

Args:
version: Define the version of the spec to use in serialization

Returns:
dict representation of current DIDDoc

"""

return {
"@context": DIDDoc.CONTEXT,
"id": canon_ref(self.did, self.did),
"publicKey": [pubkey.to_dict() for pubkey in self.pubkey.values()],
"authentication": [
{
"type": pubkey.type.authn_type,
"publicKey": canon_ref(self.did, pubkey.id),
}
for pubkey in self.pubkey.values()
if pubkey.authn
],
"service": [service.to_dict() for service in self.service.values()],
}
if version == 0:
return {
"@context": DIDDoc.CONTEXT_V0,
"id": self.did,
"publicKey": [pubkey.to_dict() for pubkey in self.pubkey.values()],
"authentication": [
{
"type": pubkey.type.authn_type,
"publicKey": canon_ref(self.did, pubkey.id),
}
for pubkey in self.pubkey.values()
if pubkey.authn
],
"service": [service.to_dict() for service in self.service.values()],
}
elif version == 1:
return {
"@context": DIDDoc.CONTEXT_V1,
"id": self.did,
"verificationMethod": [
pubkey.to_dict() for pubkey in self.pubkey.values()
],
"authentication": [
pubkey.id for pubkey in self.pubkey.values() if pubkey.authn
],
"service": [service.to_dict() for service in self.service.values()],
}
else:
raise ValueError(f"Unsupported version for serialization: {version}")

def to_json(self) -> str:
"""
@@ -228,61 +252,53 @@ def deserialize(cls, did_doc: dict) -> "DIDDoc":

"""

rv = None
if "id" in did_doc:
rv = DIDDoc(did_doc["id"])
else:
# heuristic: get DID to serve as DID document identifier from
# the first OK-looking public key
for section in ("publicKey", "authentication"):
if rv is None and section in did_doc:
for key_spec in did_doc[section]:
try:
pubkey_did = canon_did(resource(key_spec.get("id", "")))
if ok_did(pubkey_did):
rv = DIDDoc(pubkey_did)
break
except ValueError: # no identifier here, move on to next
break
if rv is None:
LOGGER.debug("no identifier in DID document")
raise ValueError("No identifier in DID document")
if "id" not in did_doc:
_parseError("no identifier in DID document")

for pubkey in did_doc.get(
"publicKey", {}
): # include all public keys, authentication pubkeys by reference
pubkey_type = PublicKeyType.get(pubkey["type"])
authn = any(
canon_ref(rv.did, ak.get("publicKey", ""))
== canon_ref(rv.did, pubkey["id"])
for ak in did_doc.get("authentication", {})
if isinstance(ak.get("publicKey", None), str)
)
key = PublicKey( # initialization canonicalizes id
rv.did,
pubkey["id"],
pubkey[pubkey_type.specifier],
pubkey_type,
canon_did(pubkey["controller"]),
authn,
)
rv.pubkey[key.id] = key
rv = DIDDoc(did_doc["id"])

auth_key_ids = set()
for akey in did_doc.get(
"authentication", {}
): # include embedded authentication keys
if "publicKey" not in akey: # not yet got it with public keys
if isinstance(akey, str):
auth_key_ids.add(canon_ref(rv.did, akey))
elif "publicKey" in akey:
# v0 representation
auth_key_ids.add(canon_ref(rv.did, akey["publicKey"]))
else:
pubkey_type = PublicKeyType.get(akey["type"])
key = PublicKey( # initialization canonicalized id
rv.did,
akey["id"],
akey[pubkey_type.specifier],
pubkey_type,
canon_did(akey["controller"]),
akey["controller"],
True,
)
if key.id in rv.pubkey:
_parseError(f"duplicate key id: {key.id}")
rv.pubkey[key.id] = key

pubkeys = did_doc.get("verificationMethod", did_doc.get("publicKey")) or {}
for (
pubkey
) in pubkeys: # include all public keys, authentication pubkeys by reference
pubkey_type = PublicKeyType.get(pubkey["type"])
key = PublicKey( # initialization canonicalizes id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could lose the comment now: it is an orphan

rv.did,
pubkey["id"],
pubkey[pubkey_type.specifier],
pubkey_type,
pubkey["controller"],
False,
)
if key.id in auth_key_ids:
key.authn = True
if key.id in rv.pubkey:
_parseError(f"duplicate key id: {key.id}")
rv.pubkey[key.id] = key

for service in did_doc.get("service", {}):
endpoint = service["serviceEndpoint"]
svc = Service( # initialization canonicalizes id
6 changes: 3 additions & 3 deletions aries_cloudagent/connections/models/diddoc/publickey.py
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@
from collections import namedtuple
from enum import Enum

from .util import canon_did, canon_ref
from .util import canon_ref


LinkedDataKeySpec = namedtuple("LinkedDataKeySpec", "ver_type authn_type specifier")
@@ -126,11 +126,11 @@ def __init__(

"""

self._did = canon_did(did)
self._did = did
self._id = canon_ref(self._did, ident)
self._value = value
self._type = pk_type or PublicKeyType.ED25519_SIG_2018
self._controller = canon_did(controller) if controller else self._did
self._controller = controller or self._did
self._authn = authn

@property
4 changes: 2 additions & 2 deletions aries_cloudagent/connections/models/diddoc/service.py
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@

from typing import List, Sequence, Union

from .util import canon_did, canon_ref
from .util import canon_ref
from .publickey import PublicKey


@@ -62,7 +62,7 @@ def __init__(

"""

self._did = canon_did(did)
self._did = did
self._id = canon_ref(self._did, ident, ";")
self._type = typ
self._recip_keys = (
Loading