This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
ssikit_trustchain/idhub_ssikit/__init__.py

148 lines
4.8 KiB
Python
Raw Normal View History

2023-11-10 05:45:12 +00:00
import asyncio
import datetime
from typing import Any
2023-11-10 05:45:12 +00:00
import didkit
import json
import jinja2
2023-11-22 13:09:08 +00:00
from jinja2 import Environment, FileSystemLoader, select_autoescape
from ast import literal_eval
2023-11-22 13:09:08 +00:00
2023-11-10 05:45:12 +00:00
def generate_did_controller_key():
return didkit.generate_ed25519_key()
def keydid_from_controller_key(key):
2023-11-10 05:45:12 +00:00
return didkit.key_to_did("key", key)
def generate_generic_vc_id():
# TODO agree on a system for Verifiable Credential IDs
return "https://pangea.org/credentials/42"
async def resolve_keydid(keydid):
return await didkit.resolve_did(keydid, "{}")
def webdid_from_controller_key(key):
"""
Se siguen los pasos para generar un webdid a partir de un keydid.
Documentado en la docu de spruceid.
"""
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"
webdid_url = f"did:web:idhub.pangea.org:{pubkeyid}" # nueva URL: "did:web:idhub.pangea.org:<...>"
webdid_url_owner = webdid_url + "#owner"
# Reemplazamos los campos del documento DID necesarios:
document["id"] = webdid_url
document["verificationMethod"][0]["id"] = webdid_url_owner
document["verificationMethod"][0]["controller"] = webdid_url
document["authentication"][0] = webdid_url_owner
document["assertionMethod"][0] = webdid_url_owner
document_fixed_serialized = json.dumps(document)
return webdid_url, document_fixed_serialized
def render_and_sign_credential(unsigned_vc: dict, jwk_issuer):
2023-11-10 05:45:12 +00:00
"""
Populates a VC template with data for issuance, and signs the result with the provided key.
The `vc_data` parameter must at a minimum include:
* issuer_did
* subject_did
* vc_id
and must include whatever other fields are relevant for the vc_template to be instantiated.
The following field(s) will be auto-generated if not passed in `vc_data`:
* issuance_date (to `datetime.datetime.now()`)
"""
async def inner():
signed_vc = await didkit.issue_credential(
json.dumps(unsigned_vc),
2023-11-10 05:45:12 +00:00
'{"proofFormat": "ldp"}',
jwk_issuer
)
return signed_vc
# if vc_data.get("issuance_date") is None:
# vc_data["issuance_date"] = datetime.datetime.now().replace(microsecond=0).isoformat()
2023-11-10 05:45:12 +00:00
return asyncio.run(inner())
def sign_credential(unsigned_vc: str, jwk_issuer):
"""
Signs the unsigned credential with the provided key.
"""
async def inner():
signed_vc = await didkit.issue_credential(
unsigned_vc,
'{"proofFormat": "ldp"}',
jwk_issuer
)
return signed_vc
return asyncio.run(inner())
def verify_credential(vc):
2023-11-10 05:45:12 +00:00
"""
Returns a (bool, str) tuple indicating whether the credential is valid.
Checks performed:
* The credential is valid in signature and form, and
* The credential validates itself against its declared schema.
2023-11-10 05:45:12 +00:00
If the boolean is true, the credential is valid and the second argument can be ignored.
If it is false, the VC is invalid and the second argument contains a string (which is a valid JSON object) with further information.
2023-11-10 05:45:12 +00:00
"""
async def inner():
str_res = await didkit.verify_credential(vc, '{"proofFormat": "ldp"}')
res = literal_eval(str_res)
ok = res["warnings"] == [] and res["errors"] == []
return ok, str_res
(ok, res) = asyncio.run(inner())
if not ok:
# The credential doesn't pass signature checks, so early return
return ok, res
return ok, res
2023-11-10 05:45:12 +00:00
2023-11-22 13:09:08 +00:00
def issue_verifiable_presentation(vc_list: list[str], jwk_holder: str, holder_did: str) -> str:
async def inner():
unsigned_vp = unsigned_vp_template.render(data)
signed_vp = await didkit.issue_presentation(
unsigned_vp,
'{"proofFormat": "ldp"}',
jwk_holder
)
return signed_vp
env = Environment(
loader=FileSystemLoader("vc_templates"),
autoescape=select_autoescape()
)
unsigned_vp_template = env.get_template("verifiable_presentation.json")
data = {
"holder_did": holder_did,
"verifiable_credential_list": "[" + ",".join(vc_list) + "]"
}
return asyncio.run(inner())
2023-11-27 06:26:02 +00:00
def verify_presentation(vp):
"""
Returns a (bool, str) tuple indicating whether the credential is valid.
If the boolean is true, the credential is valid and the second argument can be ignored.
If it is false, the VC is invalid and the second argument contains a JSON object with further information.
"""
async def inner():
proof_options = '{"proofFormat": "ldp"}'
return await didkit.verify_presentation(vp, proof_options)
2023-11-27 06:26:02 +00:00
return asyncio.run(inner())