Skip to content

Commit

Permalink
feat: add input doc generation helper
Browse files Browse the repository at this point in the history
This adds an optional helper for generating an input document from a set
of keys and services. This helper is intentionally simple; it won't
cover all use cases. But when all you need is a basic document, it will
get you there without having to worry about contexts and such.

Additionally, those familiar with the did-peer-2 library will see
similarities between the helper added here and the `generate` method in
the did-peer-2 library. This is deliberate and should hopefully help
ease the transition for those adopting did:peer:4 after did:peer:2.

I accidentally made the generation of did:peer:2 actually pretty okay,
interface wise. This addition seeks to prevent that from becoming a
barrier to adoption.

Signed-off-by: Daniel Bluhm <[email protected]>
  • Loading branch information
dbluhm committed Nov 8, 2023
1 parent 84cb652 commit 571d699
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
58 changes: 58 additions & 0 deletions did_peer_4/input_doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Helpers for creating input documents for the DID method."""
from dataclasses import dataclass
from typing import Any, Dict, Literal, Optional, Sequence

RELATIONSHIPS = (
"authentication",
"assertionMethod",
"keyAgreement",
"capabilityDelegation",
"capabilityInvocation",
)

Relationship = Literal[
"authentication",
"assertionMethod",
"keyAgreement",
"capabilityDelegation",
"capabilityInvocation",
]


@dataclass
class KeySpec:
"""Key specification."""

multikey: str
relationships: Sequence[Relationship]


def input_doc_from_keys_and_services(
keys: Sequence[KeySpec], services: Optional[Sequence[dict]] = None
) -> dict:
"""Create an input document for a set of keys and services."""
input_doc: Dict[str, Any] = {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
]
}
for index, key in enumerate(keys):
ident = f"#key-{index}"
input_doc.setdefault("verificationMethod", []).append(
{
"id": ident,
"type": "Multikey",
"publicKeyMultibase": key.multikey,
}
)
for relationship in key.relationships:
if relationship not in RELATIONSHIPS:
raise ValueError(f"Invalid relationship: {relationship}")

input_doc.setdefault(relationship, []).append(ident)

if services:
input_doc["service"] = services

return input_doc
64 changes: 64 additions & 0 deletions tests/test_input_doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from did_peer_4 import encode
from did_peer_4.input_doc import input_doc_from_keys_and_services, KeySpec
from did_peer_4.valid import validate_input_document

ED25519_MULTIKEY = "z6MkrCD1csqtgdj8sjrsu8jxcbeyP6m7LiK87NzhfWqio5yr"
X25519_MULTIKEY = "z6LSqPZfn9krvgXma2icTMKf2uVcYhKXsudCmPoUzqGYW24U"


def test_input_doc_generation():
input_doc = input_doc_from_keys_and_services(
[
KeySpec(
multikey=ED25519_MULTIKEY,
relationships=["authentication"],
),
KeySpec(
multikey=X25519_MULTIKEY,
relationships=["keyAgreement"],
),
],
[
{
"id": "#didcommmessaging-0",
"type": "DIDCommMessaging",
"serviceEndpoint": {
"uri": "didcomm:transport/queue",
"accept": ["didcomm/v2"],
},
}
],
)

assert input_doc == {
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
],
"verificationMethod": [
{
"id": "#key-0",
"type": "Multikey",
"publicKeyMultibase": ED25519_MULTIKEY,
},
{
"id": "#key-1",
"type": "Multikey",
"publicKeyMultibase": X25519_MULTIKEY,
},
],
"authentication": ["#key-0"],
"keyAgreement": ["#key-1"],
"service": [
{
"id": "#didcommmessaging-0",
"type": "DIDCommMessaging",
"serviceEndpoint": {
"uri": "didcomm:transport/queue",
"accept": ["didcomm/v2"],
},
}
],
}
assert validate_input_document(input_doc)
assert encode(input_doc)

0 comments on commit 571d699

Please sign in to comment.