From 737d2a7dceb93e885775db96c2bfd318b8019ba8 Mon Sep 17 00:00:00 2001 From: Daniel Armengod Date: Mon, 27 Nov 2023 07:04:30 +0100 Subject: [PATCH] Verifier portal backchannel endpoint --- idhub/urls.py | 4 +++ idhub/verification_portal/__init__.py | 0 idhub/verification_portal/models.py | 21 +++++++++++++ idhub/verification_portal/views.py | 43 +++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 69 insertions(+) create mode 100644 idhub/verification_portal/__init__.py create mode 100644 idhub/verification_portal/models.py create mode 100644 idhub/verification_portal/views.py diff --git a/idhub/urls.py b/idhub/urls.py index 785f4d1..80dd103 100644 --- a/idhub/urls.py +++ b/idhub/urls.py @@ -20,6 +20,7 @@ from django.urls import path, reverse_lazy from .views import LoginView from .admin import views as views_admin from .user import views as views_user +from .verification_portal import views as views_verification_portal app_name = 'idhub' @@ -171,4 +172,7 @@ urlpatterns = [ name='admin_import'), path('admin/import/new', views_admin.ImportAddView.as_view(), name='admin_import_add'), + + path('verification_portal/verify/', views_verification_portal.verify, + name="verification_portal_verify") ] diff --git a/idhub/verification_portal/__init__.py b/idhub/verification_portal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/idhub/verification_portal/models.py b/idhub/verification_portal/models.py new file mode 100644 index 0000000..c8e1615 --- /dev/null +++ b/idhub/verification_portal/models.py @@ -0,0 +1,21 @@ +from django.db import models + + +class VPVerifyRequest(models.Model): + """ + `nonce` is an opaque random string used to lookup verification requests + `expected_credentials` is a JSON list of credential types that must be present in this VP. + Example: ["FinancialSituationCredential", "HomeConnectivitySurveyCredential"] + `expected_contents` is a JSON object that places optional constraints on the contents of the + returned VP. + Example: [{"FinancialSituationCredential": {"financial_vulnerability_score": "7"}}] + `action` is (for now) a JSON object describing the next steps to take if this verification + is successful. For example "send mail to with and " + Example: {"action": "send_mail", "params": {"to": "orders@somconnexio.coop", "subject": "New client", "body": ...} + `submitted_on` is used (by a cronjob) to purge old entries that didn't complete verification + """ + nonce = models.CharField(max_length=50) + expected_credentials = models.CharField(max_length=255) + expected_contents = models.TextField() + action = models.TextField() + submitted_on = models.DateTimeField(auto_now=True) diff --git a/idhub/verification_portal/views.py b/idhub/verification_portal/views.py new file mode 100644 index 0000000..afc922b --- /dev/null +++ b/idhub/verification_portal/views.py @@ -0,0 +1,43 @@ +import json + +from django.core.mail import send_mail +from django.http import HttpResponse +from .models import VPVerifyRequest +from django.shortcuts import get_object_or_404 +from more_itertools import flatten, unique_everseen + + +def verify(request): + assert request.method == "POST" + # TODO: use request.POST["presentation_submission"] + vp = json.loads(request.POST["vp_token"]) + nonce = vp["nonce"] + # "vr" = verification_request + vr = get_object_or_404(VPVerifyRequest, nonce=nonce) # TODO: return meaningful error, not 404 + # Get a list of all included verifiable credential types + included_credential_types = unique_everseen(flatten([ + vc["type"] for vc in vp["verifiableCredential"] + ])) + # Check that it matches what we requested + for requested_vc_type in json.loads(vr.expected_credentials): + if requested_vc_type not in included_credential_types: + raise Exception("You're missing some credentials we requested!") # TODO: return meaningful error + # Perform whatever action we have to do + action = json.loads(vr.action) + if action["action"] == "send_mail": + subject = action["params"]["subject"] + to_email = action["params"]["to"] + from_email = "noreply@verifier-portal" + body = request.POST["vp-token"] + send_mail( + subject, + body, + from_email, + [to_email] + ) + elif action["action"] == "something-else": + pass + else: + raise Exception("Unknown action!") + return HttpResponse("OK! Your verifiable presentation was successfully presented.") + diff --git a/requirements.txt b/requirements.txt index 745c483..83aea96 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,3 +10,4 @@ didkit==0.3.2 jinja2==3.1.2 jsonref==1.1.0 pyld==2.0.3 +more-itertools==10.1.0