From a3922a063a04409ff9debe2f37cde8e39a861ef2 Mon Sep 17 00:00:00 2001 From: Daniel Armengod Date: Tue, 28 Nov 2023 09:45:06 +0100 Subject: [PATCH] Full functionality and verified membership-card template renders correctly --- idhub_ssikit/__init__.py | 24 +++++-- main.py | 49 ++++++++++++-- vc_templates/membership-card.json | 105 ++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 vc_templates/membership-card.json diff --git a/idhub_ssikit/__init__.py b/idhub_ssikit/__init__.py index 1a85a43..391308f 100644 --- a/idhub_ssikit/__init__.py +++ b/idhub_ssikit/__init__.py @@ -6,12 +6,11 @@ import jinja2 from jinja2 import Environment, FileSystemLoader, select_autoescape - def generate_did_controller_key(): return didkit.generate_ed25519_key() -def keydid_from_key(key): +def keydid_from_controller_key(key): return didkit.key_to_did("key", key) @@ -48,14 +47,29 @@ def render_and_sign_credential(vc_template: jinja2.Template, jwk_issuer, vc_data return asyncio.run(inner()) -def verify_credential(vc, proof_options): +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): """ 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(): - return didkit.verify_credential(vc, proof_options) + return await didkit.verify_credential(vc, '{"proofFormat": "ldp"}') return asyncio.run(inner()) @@ -91,6 +105,6 @@ def verify_presentation(vp): """ async def inner(): proof_options = '{"proofFormat": "ldp"}' - return didkit.verify_presentation(vp, proof_options) + return await didkit.verify_presentation(vp, proof_options) return asyncio.run(inner()) diff --git a/main.py b/main.py index 1b4b307..5d72805 100644 --- a/main.py +++ b/main.py @@ -22,18 +22,54 @@ def issue_vc_test(): "issuer_did": did_issuer, "subject_did": did_subject, "issuance_date": "2020-08-19T21:41:50Z", - + "validUntil": "2020-08-19T21:41:50Z", + "membershipType": "lareputa" } signed_credential = idhub_ssikit.render_and_sign_credential( unsigned_vc_template, jwk_issuer, data ) - print(signed_credential) -def issue_vp_test(): +def issue_vc_test_2(): + jwk_issuer = didkit.generate_ed25519_key() + jwk_subject = didkit.generate_ed25519_key() + + did_issuer = didkit.key_to_did("key", jwk_issuer) + did_subject = didkit.key_to_did("key", jwk_subject) + + env = Environment( + loader=FileSystemLoader("vc_templates"), + autoescape=select_autoescape() + ) + unsigned_vc_template = env.get_template("membership-card.json") + data = { + "vc_id": "http://example.org/credentials/3731", + "issuer_did": did_issuer, + "subject_did": did_subject, + "issuance_date": "2020-08-19T21:41:50Z", + "validUntil": "2020-08-19T21:41:50Z", + "membershipType": "lareputa" + } + signed_credential = idhub_ssikit.render_and_sign_credential( + unsigned_vc_template, + jwk_issuer, + data + ) + print(signed_credential) + verification_result = idhub_ssikit.verify_credential(signed_credential) + print(verification_result) + def replace(s, position, character): + return s[:position] + character + s[position+1:] + signed_credential = replace(signed_credential, 2843, "k") + verification_result = idhub_ssikit.verify_credential(signed_credential) + print(verification_result) + + + +def issue_and_sign_vp_test(): """ In this example execution two Verifiable Credentials associated with a single Holder are issued and then combined into a single Verifiable Presentation. @@ -78,6 +114,11 @@ def issue_vp_test(): jwk_issuer2, data2 ) - signed_presentation = idhub_ssikit.issue_verifiable_presentation([signed_credential, signed_credential2], jwk_subject, did_subject) + print("##############--- SIGNED PRESENTATION ---##############") print(signed_presentation) + print("##############--- ------------------- ---##############") + + res = idhub_ssikit.verify_presentation(signed_presentation) + print(res) + diff --git a/vc_templates/membership-card.json b/vc_templates/membership-card.json new file mode 100644 index 0000000..bc315bb --- /dev/null +++ b/vc_templates/membership-card.json @@ -0,0 +1,105 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + { + "individual": "https://schema.org/Person", + "Member": "https://schema.org/Member", + "startDate": "https://schema.org/startDate", + "jsonSchema": "https://schema.org/jsonSchema", + "$ref": "https://schema.org/jsonSchemaRef", + "credentialSchema": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#credentialSchema", + "organisation": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#organisation", + "membershipType": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#membershipType", + "membershipId": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#membershipId", + "typeOfPerson": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#typeOfPerson", + "identityDocType": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#identityDocType", + "identityNumber": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#identityNumber", + "name": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#name", + "description": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#description", + "value": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#value", + "lang": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#lang", + "surnames": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#surnames", + "email": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#email", + "affiliatedSince": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#affiliatedSince", + "affiliatedUntil": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#affiliatedUntil", + "issued": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#issued", + "validFrom": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#validFrom", + "validUntil": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#validUntil" + } + ], + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "MembershipCard" + ], + "id": "{{ vc_id }}", + "issuer": { + "id": "{{ issuer_did }}", + "name": "Pangea", + "description": [ + { + "value": "Pangea.org is a service provider leveraging open-source technologies to provide affordable and accessible solutions for social enterprises and solidarity organisations.", + "lang": "en" + }, + { + "value": "Pangea.org és un proveïdor de serveis que aprofita les tecnologies de codi obert per oferir solucions assequibles i accessibles per a empreses socials i organitzacions solidàries.", + "lang": "ca_ES" + }, + { + "value": "Pangea.org es un proveedor de servicios que aprovecha tecnologías de código abierto para proporcionar soluciones asequibles y accesibles para empresas sociales y organizaciones solidarias.", + "lang": "es" + } + + ] + }, + "issuanceDate": "{{ issuance_date }}", + "issued": "{{ issuance_date }}", + "validFrom": "{{ issuance_date }}", + "validUntil": "{{ validUntil }}", + "name": [ + { + "value": "Membership Card", + "lang": "en" + }, + { + "value": "Carnet de soci/a", + "lang": "ca_ES" + }, + { + "value": "Carnet de socio/a", + "lang": "es" + } + ], + "description": [ + { + "value": "The membership card specifies an individual's subscription or enrollment in specific services or benefits issued by an organization.", + "lang": "en" + }, + { + "value": "El carnet de soci especifica la subscripció o la inscripció d'un individu en serveis o beneficis específics emesos per una organització.", + "lang": "ca_ES" + }, + { + "value": "El carnet de socio especifica la suscripción o inscripción de un individuo en servicios o beneficios específicos emitidos por uns organización.", + "lang": "es" + } + ], + "credentialSubject": { + "id": "{{ subject_did }}", + "organisation": "Pangea", + "membershipType": "{{ membershipType }}", + "membershipId": "{{ vc_id }}", + "affiliatedSince": "{{ affiliatedSince }}", + "affiliatedUntil": "{{ affiliatedUntil }}", + "typeOfPerson": "{{ typeOfPerson }}", + "identityDocType": "{{ identityDocType }}", + "identityNumber": "{{ identityNumber }}", + "name": "{{ first_name }}", + "surnames": "{{ last_name }}", + "email": "{{ email }}", + "credentialSchema": { + "id": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/membership-card-schema.json", + "type": "JsonSchema" + } + } +} \ No newline at end of file