Skip to content

Commit

Permalink
updated dependencies and reformatting
Browse files Browse the repository at this point in the history
Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca>
  • Loading branch information
PatStLouis committed Oct 4, 2024
1 parent 488ad7e commit 7d6d495
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 75 deletions.
2 changes: 2 additions & 0 deletions server/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

api_router = APIRouter()


@api_router.get("/server/status", tags=["Server"], include_in_schema=False)
async def server_status():
return JSONResponse(status_code=200, content={"status": "ok"})


api_router.include_router(identifiers.router)

app.include_router(api_router)
33 changes: 20 additions & 13 deletions server/app/models/did_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
import validators


DID_WEB_REGEX = re.compile(
"did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)"
)
DID_WEB_REGEX = re.compile("did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)")

DID_WEB_ID_REGEX = re.compile(
"did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)#([a-z0-9._%-]+)"
)


class BaseModel(BaseModel):
def model_dump(self, **kwargs) -> Dict[str, Any]:
return super().model_dump(by_alias=True, exclude_none=True, **kwargs)


class VerificationMethod(BaseModel):
id: str = Field()
type: Union[str, List[str]] = Field()
Expand All @@ -27,27 +27,31 @@ class VerificationMethod(BaseModel):
@field_validator("id")
@classmethod
def verification_method_id_validator(cls, value):
assert value.startswith(f'did:web:{settings.DOMAIN}')
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value

@field_validator("type")
@classmethod
def verification_method_type_validator(cls, value):
assert value in ['Multikey', 'JsonWebKey'], 'Expected type Multikey or JsonWebKey'
assert value in [
"Multikey",
"JsonWebKey",
], "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}')
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value


class JsonWebKey(BaseModel):
kty: str = Field('OKP')
crv: str = Field('Ed25519')
x: str = Field(example='jihLNQ0eeR8OR-bgVxiUNOTP0tDKs5WKypYN0J5SJ9I')
kty: str = Field("OKP")
crv: str = Field("Ed25519")
x: str = Field(example="jihLNQ0eeR8OR-bgVxiUNOTP0tDKs5WKypYN0J5SJ9I")


class VerificationMethodJwk(VerificationMethod):
publicKeyJwk: JsonWebKey = Field()
Expand All @@ -58,6 +62,7 @@ def verification_method_public_key_validator(cls, value):
# TODO decode b64
return value


class VerificationMethodMultikey(VerificationMethod):
publicKeyMultibase: str = Field()

Expand All @@ -67,7 +72,7 @@ def verification_method_public_key_validator(cls, value):
try:
multibase.decode(value)
except:
assert False, f'Unable to decode public key multibase value {value}'
assert False, f"Unable to decode public key multibase value {value}"
return value


Expand All @@ -79,13 +84,13 @@ class Service(BaseModel):
@field_validator("id")
@classmethod
def service_id_validator(cls, value):
assert value.startswith(f'did:web:{settings.DOMAIN}')
assert value.startswith(f"did:web:{settings.DOMAIN}")
return value

@field_validator("serviceEndpoint")
@classmethod
def service_endpoint_validator(cls, value):
assert validators.url(value) , f"Invalid service endpoint {value}."
assert validators.url(value), f"Invalid service endpoint {value}."
return value


Expand All @@ -98,7 +103,9 @@ class DidDocument(BaseModel):
description: str = Field(None)
controller: str = Field(None)
alsoKnownAs: List[str] = Field(None)
verificationMethod: List[Union[VerificationMethodMultikey, VerificationMethodJwk]] = Field()
verificationMethod: List[
Union[VerificationMethodMultikey, VerificationMethodJwk]
] = Field()
authentication: List[Union[str, VerificationMethod]] = Field()
assertionMethod: List[Union[str, VerificationMethod]] = Field()
keyAgreement: List[Union[str, VerificationMethod]] = Field(None)
Expand Down
14 changes: 3 additions & 11 deletions server/app/plugins/askar.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,15 @@ async def store(self, category, data_key, data):
store = await self.open()
try:
async with store.session() as session:
await session.insert(
category,
data_key,
json.dumps(data)
)
await session.insert(category, data_key, json.dumps(data))
except:
raise HTTPException(status_code=404, detail="Couldn't store record.")

async def update(self, category, data_key, data):
store = await self.open()
try:
async with store.session() as session:
await session.replace(
category,
data_key,
json.dumps(data)
)
await session.replace(category, data_key, json.dumps(data))
except:
raise HTTPException(status_code=404, detail="Couldn't update record.")

Expand Down Expand Up @@ -103,7 +95,7 @@ def assert_proof_options(self, proof, did):
raise HTTPException(status_code=400, detail=str(msg))

def verify_proof(self, document, proof):
self.assert_proof_options(proof, document['id'])
self.assert_proof_options(proof, document["id"])

multikey = proof["verificationMethod"].split("#")[-1]

Expand Down
67 changes: 37 additions & 30 deletions server/app/routers/identifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ async def request_did(
status_code=200,
content={
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1"
],
"id": did
"@context": ["https://www.w3.org/ns/did/v1"],
"id": did,
},
"proofOptions": AskarVerifier().create_proof_config(did),
},
Expand All @@ -34,56 +32,65 @@ async def request_did(

@router.post("/{namespace}/{identifier}")
async def register_did(
namespace: str, identifier: str, request_body: RegisterDID,
namespace: str,
identifier: str,
request_body: RegisterDID,
):
did_document = request_body.model_dump()['didDocument']
did_document = request_body.model_dump()["didDocument"]
did = f"{settings.DID_WEB_BASE}:{namespace}:{identifier}"

await identifier_available(did)

# Ensure correct endpoint is called
if did_document['id'] != did:
if did_document["id"] != did:
raise HTTPException(status_code=400, detail="Location mismatch.")

# Assert proof set
proof_set = did_document.pop("proof", None)
if len(proof_set) != 2:
raise HTTPException(status_code=400, detail="Expecting proof set.")

# Find proof matching endorser
endorser_proof = next((
proof for proof in proof_set
if proof['verificationMethod'] ==
f"did:key:{settings.ENDORSER_MULTIKEY}#{settings.ENDORSER_MULTIKEY}"
), None)

endorser_proof = next(
(
proof
for proof in proof_set
if proof["verificationMethod"]
== f"did:key:{settings.ENDORSER_MULTIKEY}#{settings.ENDORSER_MULTIKEY}"
),
None,
)

# Find proof matching client
client_proof = next((
proof for proof in proof_set
if proof['verificationMethod'] !=
f"did:key:{settings.ENDORSER_MULTIKEY}#{settings.ENDORSER_MULTIKEY}"
), None)

client_proof = next(
(
proof
for proof in proof_set
if proof["verificationMethod"]
!= f"did:key:{settings.ENDORSER_MULTIKEY}#{settings.ENDORSER_MULTIKEY}"
),
None,
)

if client_proof and endorser_proof:
# Verify proofs
AskarVerifier().verify_proof(did_document, client_proof)
AskarVerifier().verify_proof(did_document, endorser_proof)
authorized_key = client_proof['verificationMethod'].split('#')[-1]
authorized_key = client_proof["verificationMethod"].split("#")[-1]

# TODO implement registration queue
# await AskarStorage().store("didRegistration", did, did_document)

# Store document and authorized key
await AskarStorage().store("didDocument", did, did_document)
await AskarStorage().store("authorizedKey", did, authorized_key)
return JSONResponse(status_code=201, content={"didDocument": did_document})

raise HTTPException(status_code=400, detail="Missing expected proof.")


@router.get("/{namespace}/{identifier}/did.json", include_in_schema=False)
async def get_did_document(
namespace: str, identifier: str
):
async def get_did_document(namespace: str, identifier: str):
did = f"{settings.DID_WEB_BASE}:{namespace}:{identifier}"
did_doc = await AskarStorage().fetch("didDocument", did)
if did_doc:
Expand Down
4 changes: 2 additions & 2 deletions server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
class Settings(BaseSettings):
PROJECT_TITLE: str = "TDW Server"
PROJECT_VERSION: str = "v0"

SECRET_KEY: str = os.environ["SECRET_KEY"]

DOMAIN: str = os.environ["DOMAIN"]
DID_WEB_BASE: str = f"did:web:{DOMAIN}"
ENDORSER_MULTIKEY: str = os.environ["ENDORSER_MULTIKEY"]

ASKAR_DB: str = (
os.environ["POSTGRES_URI"]
if "POSTGRES_URI" in os.environ
Expand Down
Empty file added server/requirements
Empty file.
36 changes: 36 additions & 0 deletions server/requirements copy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
annotated-types==0.7.0
anyio==4.4.0
aries-askar==0.3.2
base58==2.1.1
bases==0.3.0
black==24.8.0
cached-property==1.5.2
canonicaljson==2.0.0
cffi==1.17.1
click==8.1.7
exceptiongroup==1.2.2
fastapi==0.112.0
h11==0.14.0
idna==3.10
inflection==0.5.1
multiformats==0.3.1.post4
multiformats-config==0.3.1
mypy-extensions==1.0.0
packaging==24.1
pathspec==0.12.1
platformdirs==4.3.2
pycparser==2.22
pydantic==2.9.2
pydantic-settings==2.5.2
pydantic_core==2.24.0
pydid==0.5.1
PyNaCl==1.5.0
python-dotenv==1.0.1
ruff==0.6.2
sniffio==1.3.1
starlette==0.39.2
tomli==2.0.1
typing-validation==1.2.11.post4
typing_extensions==4.12.2
uvicorn==0.30.6
validators==0.34.0
25 changes: 6 additions & 19 deletions server/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,23 @@
annotated-types==0.7.0
anyio==4.4.0
anyio==4.6.0
aries-askar==0.3.2
base58==2.1.1
bases==0.3.0
black==24.8.0
cached-property==1.5.2
canonicaljson==2.0.0
cffi==1.17.1
click==8.1.7
exceptiongroup==1.2.2
fastapi==0.112.0
fastapi==0.115.0
h11==0.14.0
idna==3.10
inflection==0.5.1
multiformats==0.3.1.post4
multiformats-config==0.3.1
mypy-extensions==1.0.0
packaging==24.1
pathspec==0.12.1
platformdirs==4.3.2
pycparser==2.22
pydantic==2.9.2
pydantic-settings==2.5.2
pydantic_core==2.24.0
pydid==0.5.1
PyNaCl==1.5.0
pydantic_core==2.23.4
python-dotenv==1.0.1
ruff==0.6.2
ruff==0.6.9
sniffio==1.3.1
starlette==0.39.2
tomli==2.0.1
starlette==0.38.6
typing-validation==1.2.11.post4
typing_extensions==4.12.2
uvicorn==0.30.6
uvicorn==0.31.0
validators==0.34.0

0 comments on commit 7d6d495

Please sign in to comment.