import asyncio from typing import Callable, Any import didkit import json from jinja2 import Environment, FileSystemLoader, select_autoescape import idhub_ssikit from ast import literal_eval import copy def deep_merge_dict_inplace(d1: dict, d2: dict): """ Implements d1 |= d2, but recursively. Merges d1 and d2, giving preference to keys in d2. Keys in d1 but not in d2 are left as-is. """ for key, val in d2.items(): if isinstance(d1.get(key, None), dict) and isinstance(val, dict): deep_merge_dict_inplace(d1[key], val) continue d1[key] = val def deep_merge_dict(d1: dict, d2: dict) -> dict: """ Implements d1 | d2, but recursively. Merges d1 and d2, giving preference to keys in d2. Keys in d1 but not in d2 are left as-is. """ d1 = copy.deepcopy(d1) deep_merge_dict_inplace(d1, d2) return d1 def deep_filter_dict(f: Callable[[Any], bool], d: dict): """ Implements builtin filter(), but recursively. Applies f to all k,v pairs in d. If some v is a dict, recurse into v instead of applying f(v) directly. """ for key, val in d.items(): if isinstance(val, dict): yield key, dict(deep_filter_dict(f, val)) elif f(val): yield key, val def test_all_vcs(use_webdid=False): vcs = [ 'membership-card', 'financial-vulnerability', 'course-credential', 'federation-membership', 'e-operator-claim' ] for vc in vcs: print(f"trying {vc}... ", end="") try: if use_webdid: signed_cred = did_web_issue_vc_test_newstyle(vc) else: signed_cred = issue_vc_test_newstyle(vc) ok, err = idhub_ssikit.verify_credential(signed_cred) if ok: print("OK") else: print("FAILED!", err) open(f'/tmp/{vc}', mode='w').write(signed_cred) except Exception as e: print("FAILED! With exception:") print(e) def did_web_issue_vc_test_newstyle(vc_name): jwk_issuer = '{"kty":"OKP","crv":"Ed25519","x":"piojLFIHQ4Z6heRuPI87nrfMJKdet1dJIPG15iGjmDE","d":"zpOBTDrp_iNQTY5nZlIxLA34Sl7FXWXNGehFktznxTM"}' jwk_subject = '{"kty":"OKP","crv":"Ed25519","x":"BuKyt44QKYSX6kmAt771ai37lIFNwYlhugWXPiqcyYU","d":"qbvMhSCPKvQ-vSkqNr3q8gWY5zPUj7ry0t2YnmT7agc"}' did_issuer = "did:web:idhub.pangea.org" did_subject = didkit.key_to_did("key", jwk_subject) vc_template = json.load(open(f'../../schemas/vc_templates/{vc_name}.json')) data_base = json.load(open(f'../../schemas/vc_examples/base--data.json')) data_base["issuer"]["id"] = did_issuer data_base["credentialSubject"]["id"] = did_subject data_specific = json.load(open(f'../../schemas/vc_examples/{vc_name}--data.json')) data = deep_merge_dict(data_base, data_specific) vc_rendered_unsigned = deep_merge_dict(vc_template, data) signed_credential = idhub_ssikit.render_and_sign_credential( vc_rendered_unsigned, jwk_issuer, ) return signed_credential def issue_vc_test_newstyle(vc_name): 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) vc_template = json.load(open(f'../../schemas/vc_templates/{vc_name}.json')) data_base = json.load(open(f'../../schemas/vc_examples/base--data.json')) data_base["issuer"]["id"] = did_issuer data_base["credentialSubject"]["id"] = did_subject data_specific = json.load(open(f'../../schemas/vc_examples/{vc_name}--data.json')) data = deep_merge_dict(data_base, data_specific) vc_rendered_unsigned = deep_merge_dict(vc_template, data) signed_credential = idhub_ssikit.render_and_sign_credential( vc_rendered_unsigned, jwk_issuer, ) return signed_credential def issue_vc_test_and_fail_verification(vc_name): signed_credential = issue_vc_test_newstyle(vc_name) 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, (len(signed_credential)//4)*3, ".") 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. The Verifiable Credentials are of two different models. The use-case is meant to mimic - Holder being a physical person, - Issuer A being "Pare Manel" foundation, - Issuer B being "EXO" foundation, - Verifier (not pictured) being "Som Connexio", which wants verifiable data of the Holder from both Issuers. """ jwk_issuer = didkit.generate_ed25519_key() jwk_issuer2 = didkit.generate_ed25519_key() jwk_subject = didkit.generate_ed25519_key() did_issuer = didkit.key_to_did("key", jwk_issuer) did_issuer2 = didkit.key_to_did("key", jwk_issuer2) did_subject = didkit.key_to_did("key", jwk_subject) print(did_issuer) print(did_issuer2) print(did_subject) # TODO: WE'RE NO LONGER USING JINJA2 env = Environment( loader=FileSystemLoader("vc_templates"), autoescape=select_autoescape() ) unsigned_vc_template = env.get_template("member.json") data = { "vc_id": "http://example.org/credentials/3731", "issuer_did": did_issuer, "subject_did": did_subject, "issuance_date": "2020-08-19T21:41:50Z", "subject_is_member_of": "Pangea" } signed_credential = idhub_ssikit.render_and_sign_credential( unsigned_vc_template, jwk_issuer, data ) data2 = data data2["issuer_did"] = did_issuer2 signed_credential2 = idhub_ssikit.render_and_sign_credential( unsigned_vc_template, 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) def scratch(): jwk_issuer = didkit.generate_ed25519_key() did_issuer = didkit.key_to_did("key", jwk_issuer)