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

Initial set of tests #84

Merged
merged 11 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 6 additions & 30 deletions server/app/models/did_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def verification_method_controller_validator(cls, value):
class JsonWebKey(BaseModel):
kty: str = Field("OKP")
crv: str = Field("Ed25519")
x: str = Field(example="jihLNQ0eeR8OR-bgVxiUNOTP0tDKs5WKypYN0J5SJ9I")
x: str = Field()


class VerificationMethodJwk(VerificationMethod):
Expand Down Expand Up @@ -96,7 +96,7 @@ def service_endpoint_validator(cls, value):

class DidDocument(BaseModel):
context: Union[str, List[str]] = Field(
["https://www.w3.org/ns/did/v1", "https://w3id.org/security/multikey/v1"],
["https://www.w3.org/ns/did/v1"],
alias="@context",
)
id: str = Field()
Expand All @@ -106,9 +106,9 @@ class DidDocument(BaseModel):
alsoKnownAs: List[str] = Field(None)
verificationMethod: List[
Union[VerificationMethodMultikey, VerificationMethodJwk]
] = Field()
authentication: List[Union[str, VerificationMethod]] = Field()
assertionMethod: List[Union[str, VerificationMethod]] = Field()
] = Field(None)
authentication: List[Union[str, VerificationMethod]] = Field(None)
assertionMethod: List[Union[str, VerificationMethod]] = Field(None)
keyAgreement: List[Union[str, VerificationMethod]] = Field(None)
capabilityInvocation: List[Union[str, VerificationMethod]] = Field(None)
capabilityDelegation: List[Union[str, VerificationMethod]] = Field(None)
Expand All @@ -126,30 +126,6 @@ def id_validator(cls, value):
assert DID_WEB_REGEX.match(value), "Expected id to be a DID."
return value

@field_validator("authentication")
@classmethod
def authentication_validator(cls, value):
assert len(value) >= 1, "Expected at least one authentication method."
return value

@field_validator("assertionMethod")
@classmethod
def assertion_method_validator(cls, value):
assert len(value) >= 1, "Expected at least one assertion method."
return value

@field_validator("verificationMethod")
@classmethod
def verification_method_validator(cls, value):
assert len(value) >= 1, "Expected at least one verification method."
return value


class SecuredDidDocument(DidDocument):
proof: List[DataIntegrityProof] = Field(None)

@field_validator("proof")
@classmethod
def proof_validator(cls, value):
assert len(value) == 2, "Expected proof set."
return value
proof: Union[DataIntegrityProof, List[DataIntegrityProof]] = Field(None)
1 change: 1 addition & 0 deletions server/app/plugins/askar.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ def verify_proof(self, document, proof):
raise HTTPException(
status_code=400, detail="Signature was forged or corrupt."
)
return True
except:
raise HTTPException(status_code=400, detail="Error verifying proof.")
6 changes: 3 additions & 3 deletions server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ class Settings(BaseSettings):
PROJECT_TITLE: str = "DID WebVH Server"
PROJECT_VERSION: str = "v0"

SECRET_KEY: str = os.environ["SECRET_KEY"]
SECRET_KEY: str = os.environ.get("SECRET_KEY", "s3cret")

DOMAIN: str = os.environ["DOMAIN"]
DOMAIN: str = os.environ.get("DOMAIN", "localhost")
DID_WEB_PREFIX: str = "did:web:"
DID_WEBVH_PREFIX: str = "did:webvh:"
DID_WEB_BASE: str = f"{DID_WEB_PREFIX}{DOMAIN}"
ENDORSER_MULTIKEY: str = os.environ["ENDORSER_MULTIKEY"]
ENDORSER_MULTIKEY: str = os.environ.get("ENDORSER_MULTIKEY", "")

POSTGRES_USER: str = os.getenv("POSTGRES_USER", "")
POSTGRES_PASSWORD: str = os.getenv("POSTGRES_PASSWORD", "")
Expand Down
Empty file added server/tests/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions server/tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from config import settings
from app.models.did_document import DidDocument, SecuredDidDocument
from app.models.di_proof import DataIntegrityProof

TEST_DOMAIN = settings.DOMAIN
TEST_DID_NAMESPACE = 'test'
TEST_DID_IDENTIFIER = '01'
TEST_DID = f"{settings.DID_WEB_BASE}:{TEST_DID_NAMESPACE}:{TEST_DID_IDENTIFIER}"
TEST_PROOF_OPTIONS = {
'type': 'DataIntegrityProof',
'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='z4NCh2bocHncp9SSpCDETSsWN5ueu7eLPFgaVTNvgCk2RxZvFbVHAN8keGqd8XXbSzrxd3q1VMKQrZuqf672WNncK',
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()
74 changes: 74 additions & 0 deletions server/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from app.routers.identifiers import request_did
from app.routers.resolvers import get_did_document
from app.plugins import AskarStorage, AskarVerifier, DidWebVH
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 asyncio
import json
import uuid

def test_storage():
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you not make this test async and await these asynchronous functions?

askar = AskarStorage()
asyncio.run(askar.provision(recreate=True))

category = 'test'
key = '01'
data = {'value': None}
value_1 = 'value_1'
value_2 = 'value_2'

data['value'] = value_1
asyncio.run(askar.store(category, key, data))
fetched_data = asyncio.run(askar.fetch(category, key))
assert fetched_data['value'] == value_1

data['value'] = value_2
asyncio.run(askar.update(category, key, data))
fetched_data = asyncio.run(askar.fetch(category, key))
assert fetched_data['value'] == value_2

def test_request_did():
did_request = asyncio.run(request_did(TEST_DID_NAMESPACE, TEST_DID_IDENTIFIER))
did_request = json.loads(did_request.body.decode())
assert did_request.get('didDocument').get('id') == TEST_DID
assert did_request.get('proofOptions').get("type") == TEST_PROOF_OPTIONS['type']
assert did_request.get('proofOptions').get("cryptosuite") == TEST_PROOF_OPTIONS['cryptosuite']
assert did_request.get('proofOptions').get("proofPurpose") == TEST_PROOF_OPTIONS['proofPurpose']
assert did_request.get('proofOptions').get("domain") == TEST_DOMAIN
assert did_request.get('proofOptions').get("challenge")
assert datetime.fromisoformat(
did_request.get('proofOptions').get("expires")
) > datetime.now(timezone.utc)

def test_register_did():
askar = AskarStorage()
asyncio.run(askar.store("didDocument", TEST_DID, TEST_DID_DOCUMENT))
asyncio.run(askar.store("authorizedKey", TEST_DID, TEST_AUTHORISED_KEY))

def test_resolve_did():
did_doc = asyncio.run(get_did_document(TEST_DID_NAMESPACE, TEST_DID_IDENTIFIER))
did_doc = json.loads(did_doc.body.decode())
assert did_doc == TEST_DID_DOCUMENT
assert did_doc.get('id') == TEST_DID

def test_create_log_entry():
initial_log_entry = DidWebVH().create(TEST_DID_DOCUMENT, TEST_AUTHORISED_KEY)
assert initial_log_entry.get('versionId')
assert initial_log_entry.get('versionTime')
assert initial_log_entry.get('parameters')
assert initial_log_entry.get('state')

def test_verify_di_proof():
document = TEST_DID_DOCUMENT_SIGNED
proof = document.pop('proof')
verifier = AskarVerifier()
assert verifier.verify_proof(document, proof)