Skip to content

Commit

Permalink
add local test signer and log testing
Browse files Browse the repository at this point in the history
Signed-off-by: pstlouis <[email protected]>
  • Loading branch information
PatStLouis committed Jan 9, 2025
1 parent 92a7229 commit 2af5410
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 41 deletions.
42 changes: 21 additions & 21 deletions server/app/models/did_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ class VerificationMethod(BaseModel):
type: Union[str, List[str]] = Field()
controller: str = Field()

@field_validator("id")
@classmethod
def verification_method_id_validator(cls, value):
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value
# @field_validator("id")
# @classmethod
# def verification_method_id_validator(cls, value):
# assert value.startswith(f"did:web:{settings.DOMAIN}")
# return value

@field_validator("type")
@classmethod
Expand All @@ -39,12 +39,12 @@ def verification_method_type_validator(cls, value):
], "Expected type Multikey or JsonWebKey"
return value

@field_validator("controller")
@classmethod
def verification_method_controller_validator(cls, value):
assert DID_WEB_REGEX.match(value), "Expected controller to be a DID."
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value
# @field_validator("controller")
# @classmethod
# def verification_method_controller_validator(cls, value):
# assert DID_WEB_REGEX.match(value), "Expected controller to be a DID."
# assert value.startswith(f"did:web:{settings.DOMAIN}")
# return value


class JsonWebKey(BaseModel):
Expand Down Expand Up @@ -81,11 +81,11 @@ class Service(BaseModel):
type: Union[str, List[str]] = Field()
serviceEndpoint: str = Field()

@field_validator("id")
@classmethod
def service_id_validator(cls, value):
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value
# @field_validator("id")
# @classmethod
# def service_id_validator(cls, value):
# assert value.startswith(f"did:web:{settings.DOMAIN}")
# return value

@field_validator("serviceEndpoint")
@classmethod
Expand Down Expand Up @@ -131,11 +131,11 @@ def context_validator(cls, value):
assert value[0] == "https://www.w3.org/ns/did/v1", "Invalid context."
return value

@field_validator("id")
@classmethod
def id_validator(cls, value):
assert DID_WEB_REGEX.match(value), "Expected id to be a DID."
return value
# @field_validator("id")
# @classmethod
# def id_validator(cls, value):
# assert DID_WEB_REGEX.match(value), "Expected id to be a DID."
# return value


class SecuredDidDocument(DidDocument):
Expand Down
1 change: 1 addition & 0 deletions server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
asyncio_mode=auto
asyncio_default_fixture_loop_scope = "function"
16 changes: 3 additions & 13 deletions server/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from app.models.did_document import DidDocument, SecuredDidDocument
from app.models.di_proof import DataIntegrityProof

TEST_SEED = 'ixUwS8A2SYzmPiGor7t08wgg1ifNABrB'
TEST_AUTHORISED_KEY = 'z6Mkixacx8HJ5nRBJvJKNdv83v1ejZBpz3HvRCfa2JaKbQJV'
TEST_AUTHORISED_JWK = 'QvGYHF-i-RTVnJlSDsYkSffG1GUZasgGt1yhRdv4rgI'
TEST_DOMAIN = settings.DOMAIN
TEST_DID_NAMESPACE = 'test'
TEST_DID_IDENTIFIER = '01'
Expand All @@ -11,21 +14,8 @@
'cryptosuite': 'eddsa-jcs-2022',
'proofPurpose': 'assertionMethod'
}
TEST_AUTHORISED_KEY = 'z6Mkj8h3kzWZrPiucoyY9LGCTpXhCqBoX3doDmHz5MaPxnvi'
TEST_AUTHORISED_JWK = 'RYirjVOuAh9BXxQaxozaDLK_JqrKPicZeq9bl3Fg8xc'

TEST_DID_DOCUMENT = DidDocument(
context=['https://www.w3.org/ns/did/v1'],
id=TEST_DID
).model_dump()

TEST_DID_DOCUMENT_PROOF = DataIntegrityProof(
proofValue='z5qtizN3eN3nogndvKt2GhLM4pbLceRNJYq7xi1n6yjQmd5yAzDBWrwC9VxbeFXjCoP2i8kLWRFJxGrqjAt1LFLHN',
verificationMethod=f'did:key:{TEST_AUTHORISED_KEY}#{TEST_AUTHORISED_KEY}'
).model_dump()

TEST_DID_DOCUMENT_SIGNED = SecuredDidDocument(
context=['https://www.w3.org/ns/did/v1'],
id=TEST_DID,
proof=TEST_DID_DOCUMENT_PROOF
).model_dump()
29 changes: 29 additions & 0 deletions server/tests/signer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from hashlib import sha256
import canonicaljson
from multiformats import multibase
from aries_askar import Key, KeyAlg
from aries_askar.bindings import LocalKeyHandle
from tests.fixtures import TEST_SEED, TEST_PROOF_OPTIONS

def sign(document, options=TEST_PROOF_OPTIONS):
key = Key(LocalKeyHandle()).from_seed(KeyAlg.ED25519, TEST_SEED)
pub_key_multi = multibase.encode(
bytes.fromhex(
f"ed01{key.get_public_bytes().hex()}"
),
"base58btc",
)
options['verificationMethod'] = f'did:key:{pub_key_multi}#{pub_key_multi}'

hash_data = (
sha256(canonicaljson.encode_canonical_json(options)).digest()
+ sha256(canonicaljson.encode_canonical_json(document)).digest()
)

proof = options.copy()
proof["proofValue"] = multibase.encode(
key.sign_message(hash_data), "base58btc"
)

return document | {'proof': proof}

36 changes: 29 additions & 7 deletions server/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
from app.routers.identifiers import request_did, read_did
from app.routers.identifiers import request_did, read_did, read_did_log, create_didwebvh
from app.plugins import AskarStorage, AskarVerifier, DidWebVH
from app.models.web_schemas import RegisterInitialLogEntry
from app.models.did_log import LogEntry
from datetime import datetime, timezone
from tests.fixtures import (
TEST_DOMAIN,
TEST_DID_NAMESPACE,
TEST_DID_IDENTIFIER,
TEST_DID,
TEST_DID_DOCUMENT,
TEST_DID_DOCUMENT_SIGNED,
TEST_AUTHORISED_KEY,
TEST_PROOF_OPTIONS
)
import json
import pytest
import asyncio
from tests.signer import sign

askar = AskarStorage()
asyncio.run(askar.provision(recreate=True))
Expand Down Expand Up @@ -65,6 +67,13 @@ async def test_resolve_did():
did_doc = json.loads(did_doc.body.decode())
assert did_doc == TEST_DID_DOCUMENT
assert did_doc.get('id') == TEST_DID

@pytest.mark.asyncio
async def test_verify_di_proof():
document = await askar.fetch("didDocument", TEST_DID)
signed_document = sign(document)
proof = signed_document.pop('proof')
assert verifier.verify_proof(signed_document, proof)

@pytest.mark.asyncio
async def test_create_log_entry():
Expand All @@ -73,9 +82,22 @@ async def test_create_log_entry():
assert initial_log_entry.get('versionTime')
assert initial_log_entry.get('parameters')
assert initial_log_entry.get('state')

@pytest.mark.asyncio
async def test_verify_di_proof():
document = TEST_DID_DOCUMENT_SIGNED
proof = document.pop('proof')
assert verifier.verify_proof(document, proof)
async def test_register_log_entry():
log_entry = didwebvh.create(TEST_DID_DOCUMENT, TEST_AUTHORISED_KEY)
assert log_entry.get('versionId')
assert log_entry.get('versionTime')
assert log_entry.get('parameters')
assert log_entry.get('state')
signed_log_entry = sign(log_entry)
signed_log_entry['proof'] = [signed_log_entry['proof']]
log_request = RegisterInitialLogEntry.model_validate({'logEntry': signed_log_entry})
response = await create_didwebvh(TEST_DID_NAMESPACE, TEST_DID_IDENTIFIER, log_request)
log_entry = response.body.decode()
LogEntry.model_validate(json.loads(log_entry))

@pytest.mark.asyncio
async def test_resolve_did_log():
did_logs = await read_did_log(TEST_DID_NAMESPACE, TEST_DID_IDENTIFIER)
did_logs = json.loads(did_logs.body.decode())

0 comments on commit 2af5410

Please sign in to comment.