Skip to content

Commit

Permalink
binding a kid to a did key
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick <[email protected]>
  • Loading branch information
PatStLouis committed Sep 15, 2024
1 parent fbef29d commit 09eb919
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 21 deletions.
43 changes: 39 additions & 4 deletions aries_cloudagent/did/did_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ def __init__(self, public_key: bytes = None, key_type: KeyType = None) -> None:
self._key_type = key_type

@classmethod
async def register(self, key_type: KeyType, profile: Profile):
"""Register a new key DID.
async def create(
self, key_type: KeyType, profile: Profile, kid: str = None, seed: str = None
):
"""Create a new key DID.
Args:
key_type: The key type to use for the DID
kid: An optional verification method to associate with the DID
profile: The profile to use for storing the DID keypair
Returns:
Expand All @@ -45,8 +48,40 @@ async def register(self, key_type: KeyType, profile: Profile):
"""
async with profile.session() as session:
wallet = session.inject(BaseWallet)
info = await wallet.create_local_did(method=KEY, key_type=key_type)
return info.did
did_info = await wallet.create_local_did(
method=KEY, key_type=key_type, seed=seed
)
kid = kid if kid else f"{did_info.did}#" + did_info.did.split(":")[-1]
await wallet.assign_kid_to_key(verkey=did_info.verkey, kid=kid)
await wallet.get_key_by_kid(kid=kid)
return {
"did": did_info.did,
"verificationMethod": kid,
"multikey": did_info.did.split(":")[-1],
}

@classmethod
async def bind(self, profile: Profile, did: str, kid: str):
"""Create a new key DID.
Args:
key_type: The key type to use for the DID
kid: An optional verification method to associate with the DID
profile: The profile to use for storing the DID keypair
Returns:
A string representing the created DID
Raises:
DidOperationError: If the an error occures during did registration
"""
async with profile.session() as session:
wallet = session.inject(BaseWallet)
did_info = await wallet.get_local_did(did=did)
await wallet.assign_kid_to_key(verkey=did_info.verkey, kid=kid)
await wallet.get_key_by_kid(kid=kid)
return {"did": did, "verificationMethod": kid, "multikey": did.split(":")[-1]}

@classmethod
def from_public_key(cls, public_key: bytes, key_type: KeyType) -> "DIDKey":
Expand Down
53 changes: 44 additions & 9 deletions aries_cloudagent/did/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,63 @@
from .web_requests import (
DIDKeyRegistrationRequest,
DIDKeyRegistrationResponse,
DIDKeyBindingRequest,
DIDKeyBindingResponse,
)
from . import DIDKey, DidOperationError

KEY_MAPPINGS = {"ed25519": ED25519}


@docs(tags=["did"], summary="Register Key DID")
@docs(tags=["did"], summary="Create DID Key")
@request_schema(DIDKeyRegistrationRequest())
@response_schema(DIDKeyRegistrationResponse(), 201, description="Register new DID key")
@response_schema(DIDKeyRegistrationResponse(), 201, description="Create new DID key")
@tenant_authentication
async def register_did_key(request: web.BaseRequest):
async def create_did_key(request):
"""Request handler for registering a Key DID.
Args:
request: aiohttp request object
"""
body = await request.json()
context: AdminRequestContext = request["context"]
try:
key_type = body["key_type"]
did_doc = await DIDKey().register(KEY_MAPPINGS[key_type], context.profile)
return web.json_response({"didDocument": did_doc}, status=201)
return web.json_response(
await DIDKey().create(
profile=request["context"].profile,
key_type=KEY_MAPPINGS[
request["data"]["type"] if "type" in request["data"] else "ed25519"
],
kid=request["data"]["kid"] if "kid" in request["data"] else None,
seed=request["data"]["seed"] if "seed" in request["data"] else None,
),
status=201,
)
except (KeyError, ValidationError, DidOperationError) as err:
return web.json_response({"message": str(err)}, status=400)


@docs(tags=["did"], summary="Bind DID Key")
@request_schema(DIDKeyBindingRequest())
@response_schema(
DIDKeyBindingResponse(), 201, description="Bind existing DID key to new KID"
)
@tenant_authentication
async def bind_did_key(request):
"""Request handler for binding a Key DID.
Args:
request: aiohttp request object
"""
try:
return web.json_response(
await DIDKey().bind(
profile=request["context"].profile,
did=request["data"]["did"],
kid=request["data"]["kid"],
),
status=200,
)
except (KeyError, ValidationError, DidOperationError) as err:
return web.json_response({"message": str(err)}, status=400)

Expand All @@ -42,7 +76,8 @@ async def register(app: web.Application):

app.add_routes(
[
web.post("/did/key", register_did_key),
web.post("/did/key/create", create_did_key),
web.post("/did/key/bind", bind_did_key),
]
)

Expand Down
65 changes: 57 additions & 8 deletions aries_cloudagent/did/web_requests.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""DID routes web requests schemas."""

from marshmallow import fields
from ..messaging.models.openapi import OpenAPISchema
from marshmallow import fields, Schema


class DIDKeyRegistrationRequest(OpenAPISchema):
"""Request schema for registering key dids."""
class DIDKeyRegistrationRequest(Schema):
"""Request schema for creating a dids."""

key_type = fields.Str(
type = fields.Str(
default="ed25519",
required=False,
metadata={
Expand All @@ -16,8 +15,58 @@ class DIDKeyRegistrationRequest(OpenAPISchema):
},
)

seed = fields.Str(
default=None,
required=False,
metadata={
"description": "Seed",
"example": "00000000000000000000000000000000",
},
)

kid = fields.Str(
default=None,
required=False,
metadata={
"description": "Verification Method",
"example": "did:web:example.com#key-01",
},
)


class DIDKeyRegistrationResponse(Schema):
"""Response schema for creating a did."""

did = fields.Str()
multikey = fields.Str()
verificationMethod = fields.Str()


class DIDKeyBindingRequest(Schema):
"""Request schema for binding a kid to a did."""

did = fields.Str(
default=None,
required=True,
metadata={
"description": "DID",
"example": "did:key:z6MkgKA7yrw5kYSiDuQFcye4bMaJpcfHFry3Bx45pdWh3s8i",
},
)

kid = fields.Str(
default=None,
required=True,
metadata={
"description": "Verification Method",
"example": "did:web:example.com#key-02",
},
)


class DIDKeyRegistrationResponse(OpenAPISchema):
"""Response schema for registering web dids."""
class DIDKeyBindingResponse(Schema):
"""Response schema for binding a kid to a did."""

did_document = fields.Dict()
did = fields.Str()
multikey = fields.Str()
verificationMethod = fields.Str()
1 change: 1 addition & 0 deletions aries_cloudagent/wallet/askar.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ async def create_local_did(
seed: Optional seed to use for DID
did: The DID to use
metadata: Metadata to store with DID
kid: Optional key identifier
Returns:
A `DIDInfo` instance representing the created DID
Expand Down
8 changes: 8 additions & 0 deletions aries_cloudagent/wallet/in_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ async def create_local_did(
key_type: The key type to use for the DID
seed: Optional seed to use for DID
did: The DID to use
kid: Optional kid to assign to the DID
metadata: Metadata to store with DID
Returns:
Expand Down Expand Up @@ -297,6 +298,13 @@ async def create_local_did(
"key_type": key_type,
"method": method,
}
self.profile.keys[verkey_enc] = {
"seed": seed,
"secret": secret,
"verkey": verkey_enc,
"metadata": metadata.copy() if metadata else {},
"key_type": key_type,
}
return DIDInfo(
did=did,
verkey=verkey_enc,
Expand Down

0 comments on commit 09eb919

Please sign in to comment.