Soporte para revocación
Falta de alguna manera especificar cuando se crean los did:web, que son prerequisito para revocar credenciales
This commit is contained in:
parent
e7f6153c62
commit
19183b9f86
|
@ -1,6 +1,9 @@
|
|||
import base64
|
||||
import json
|
||||
import uuid
|
||||
import zlib
|
||||
|
||||
import pyroaring
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.urls import reverse_lazy
|
||||
|
@ -82,16 +85,21 @@ def serve_did(request, did_id):
|
|||
did = get_object_or_404(DID, did=id_did)
|
||||
# Deserialize the base DID from JSON storage
|
||||
document = json.loads(did.didweb_document)
|
||||
# Has this DID issued any Verifiable Credentials? If so, we need to add a Revocation List "service"
|
||||
# entry to the DID document.
|
||||
revoked_credentials = did.verificablecredential_set.filter(status=VerificableCredential.Status.REVOKED)
|
||||
revoked_credential_indexes = []
|
||||
for credential in revoked_credentials:
|
||||
revoked_credential_indexes.append(credential.revocationBitmapIndex)
|
||||
encoded_revocation_bitmap = None # TODO
|
||||
# TODO: Conditionally add "service" to DID document only if the DID has issued any VC
|
||||
revocation_bitmap = pyroaring.BitMap(revoked_credential_indexes)
|
||||
encoded_revocation_bitmap = base64.b64encode(zlib.compress(revocation_bitmap.serialize()))
|
||||
revocation_service = [{
|
||||
"id": f"{id_did}#revocation",
|
||||
"type": "RevocationBitmap2022",
|
||||
"serviceEndpoint": f"data:application/octet-stream;base64,{encoded_revocation_bitmap}"
|
||||
}]
|
||||
document["service"] = revocation_service
|
||||
# Serialize the DID + Revocation list in preparation for sending
|
||||
document = json.dumps(document)
|
||||
retval = HttpResponse(document)
|
||||
|
|
|
@ -28,3 +28,4 @@ fontTools==4.47.0
|
|||
weasyprint==60.2
|
||||
ujson==5.9.0
|
||||
./didkit-0.3.2-cp311-cp311-manylinux_2_34_x86_64.whl
|
||||
pyroaring==0.4.5
|
|
@ -1,11 +1,15 @@
|
|||
import asyncio
|
||||
import base64
|
||||
import datetime
|
||||
import zlib
|
||||
|
||||
import didkit
|
||||
import json
|
||||
import urllib
|
||||
import jinja2
|
||||
from django.template.backends.django import Template
|
||||
from django.template.loader import get_template
|
||||
from pyroaring import BitMap
|
||||
|
||||
from trustchain_idhub import settings
|
||||
|
||||
|
@ -18,8 +22,11 @@ def keydid_from_controller_key(key):
|
|||
return didkit.key_to_did("key", key)
|
||||
|
||||
|
||||
async def resolve_keydid(keydid):
|
||||
return await didkit.resolve_did(keydid, "{}")
|
||||
def resolve_did(keydid):
|
||||
async def inner():
|
||||
return await didkit.resolve_did(keydid, "{}")
|
||||
|
||||
return asyncio.run(inner())
|
||||
|
||||
|
||||
def webdid_from_controller_key(key):
|
||||
|
@ -29,7 +36,7 @@ def webdid_from_controller_key(key):
|
|||
"""
|
||||
keydid = keydid_from_controller_key(key) # "did:key:<...>"
|
||||
pubkeyid = keydid.rsplit(":")[-1] # <...>
|
||||
document = json.loads(asyncio.run(resolve_keydid(keydid))) # Documento DID en terminos "key"
|
||||
document = json.loads(resolve_did(keydid)) # Documento DID en terminos "key"
|
||||
domain = urllib.parse.urlencode({"domain": settings.DOMAIN})[7:]
|
||||
webdid_url = f"did:web:{domain}:did-registry:{pubkeyid}" # nueva URL: "did:web:idhub.pangea.org:<...>"
|
||||
webdid_url_owner = webdid_url + "#owner"
|
||||
|
@ -105,6 +112,28 @@ def verify_credential(vc):
|
|||
if not valid:
|
||||
return valid, reason
|
||||
# Credential passes basic signature verification. Now check it against its schema.
|
||||
# TODO: check agasint schema
|
||||
pass
|
||||
# Credential verifies against its schema. Now check revocation status.
|
||||
vc = json.loads(vc)
|
||||
revocation_index = int(vc["credentialStatus"]["revocationBitmapIndex"]) # NOTE: THIS FIELD SHOULD BE SERIALIZED AS AN INTEGER, BUT IOTA DOCUMENTAITON SERIALIZES IT AS A STRING. DEFENSIVE CAST ADDED JUST IN CASE.
|
||||
vc_issuer = vc["issuer"]["id"] # This is a DID
|
||||
issuer_did_document = json.loads(resolve_did(vc_issuer)) # TODO: implement a caching layer so we don't have to fetch the DID (and thus the revocation list) every time a VC is validated.
|
||||
issuer_revocation_list = issuer_did_document["service"][0]
|
||||
assert issuer_revocation_list["type"] == "RevocationBitmap2022"
|
||||
revocation_bitmap = BitMap.deserialize(
|
||||
zlib.decompress(
|
||||
base64.b64decode(
|
||||
issuer_revocation_list["serviceEndpoint"].rsplit(",")[1]
|
||||
)
|
||||
)
|
||||
)
|
||||
if revocation_index in revocation_bitmap:
|
||||
return False, "Credential has been revoked by the issuer"
|
||||
# Fallthrough means all is good.
|
||||
return True, ""
|
||||
|
||||
|
||||
|
||||
|
||||
def issue_verifiable_presentation(vp_template: Template, vc_list: list[str], jwk_holder: str, holder_did: str) -> str:
|
||||
|
|
Loading…
Reference in a new issue