diff --git a/idhub/admin/views.py b/idhub/admin/views.py index b6dcbc8..5d8d15c 100644 --- a/idhub/admin/views.py +++ b/idhub/admin/views.py @@ -639,7 +639,7 @@ class DidRegisterView(Credentials, CreateView): icon = 'bi bi-patch-check-fill' wallet = True model = DID - fields = ('label',) + fields = ('label', 'type') success_url = reverse_lazy('idhub:admin_dids') object = None diff --git a/idhub/management/commands/initial_datas.py b/idhub/management/commands/initial_datas.py index e4e6e4d..e7082f7 100644 --- a/idhub/management/commands/initial_datas.py +++ b/idhub/management/commands/initial_datas.py @@ -64,7 +64,7 @@ class Command(BaseCommand): def create_defaults_dids(self): for u in User.objects.all(): - did = DID(label="Default", user=u) + did = DID(label="Default", user=u, type=DID.Types.KEY) did.set_did() did.save() diff --git a/idhub/migrations/0001_initial.py b/idhub/migrations/0001_initial.py index 6d87ae7..72ae46f 100644 --- a/idhub/migrations/0001_initial.py +++ b/idhub/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.5 on 2023-12-11 08:35 +# Generated by Django 4.2.5 on 2024-01-16 13:04 from django.conf import settings from django.db import migrations, models @@ -25,10 +25,17 @@ class Migration(migrations.Migration): verbose_name='ID', ), ), + ( + 'type', + models.PositiveSmallIntegerField( + choices=[(1, 'Key'), (2, 'Web')], verbose_name='Type' + ), + ), ('created_at', models.DateTimeField(auto_now=True)), - ('label', models.CharField(max_length=50)), + ('label', models.CharField(max_length=50, verbose_name='Label')), ('did', models.CharField(max_length=250)), ('key_material', models.CharField(max_length=250)), + ('didweb_document', models.TextField()), ( 'user', models.ForeignKey( @@ -256,8 +263,11 @@ class Migration(migrations.Migration): verbose_name='ID', ), ), - ('created', models.DateTimeField(auto_now=True)), - ('message', models.CharField(max_length=350)), + ('created', models.DateTimeField(auto_now=True, verbose_name='Date')), + ( + 'message', + models.CharField(max_length=350, verbose_name='Description'), + ), ( 'type', models.PositiveSmallIntegerField( @@ -295,7 +305,8 @@ class Migration(migrations.Migration): (28, 'Organisational DID deleted by admin'), (29, 'User deactivated'), (30, 'User activated'), - ] + ], + verbose_name='Event', ), ), ( @@ -327,6 +338,7 @@ class Migration(migrations.Migration): on_delete=django.db.models.deletion.CASCADE, related_name='users', to='idhub.service', + verbose_name='Service', ), ), ( diff --git a/idhub/models.py b/idhub/models.py index 6c5ed1e..c4da900 100644 --- a/idhub/models.py +++ b/idhub/models.py @@ -11,7 +11,7 @@ from utils.idhub_ssikit import ( generate_did_controller_key, keydid_from_controller_key, sign_credential, - verify_credential + webdid_from_controller_key, ) from idhub_auth.models import User @@ -406,6 +406,13 @@ class Event(models.Model): class DID(models.Model): + class Types(models.IntegerChoices): + KEY = 1, "Key" + WEB = 2, "Web" + type = models.PositiveSmallIntegerField( + _("Type"), + choices=Types.choices, + ) created_at = models.DateTimeField(auto_now=True) label = models.CharField(_("Label"), max_length=50) did = models.CharField(max_length=250) @@ -419,6 +426,7 @@ class DID(models.Model): related_name='dids', null=True, ) + didweb_document = models.TextField() @property def is_organization_did(self): @@ -428,7 +436,12 @@ class DID(models.Model): def set_did(self): self.key_material = generate_did_controller_key() - self.did = keydid_from_controller_key(self.key_material) + if self.type == self.Types.KEY: + self.did = keydid_from_controller_key(self.key_material) + elif self.type == self.Types.WEB: + didurl, document = webdid_from_controller_key(self.key_material) + self.did = didurl + self.didweb_document = document def get_key(self): return json.loads(self.key_material) diff --git a/idhub/urls.py b/idhub/urls.py index d139c32..8b92d93 100644 --- a/idhub/urls.py +++ b/idhub/urls.py @@ -17,7 +17,7 @@ Including another URLconf from django.contrib.auth import views as auth_views from django.views.generic import RedirectView from django.urls import path, reverse_lazy -from .views import LoginView +from .views import LoginView, serve_did from .admin import views as views_admin from .user import views as views_user # from .verification_portal import views as views_verification_portal @@ -173,6 +173,8 @@ urlpatterns = [ path('admin/import/new', views_admin.ImportAddView.as_view(), name='admin_import_add'), + path('did-registry/', serve_did) + # path('verification_portal/verify/', views_verification_portal.verify, # name="verification_portal_verify") ] diff --git a/idhub/user/views.py b/idhub/user/views.py index 2e1258e..29153e6 100644 --- a/idhub/user/views.py +++ b/idhub/user/views.py @@ -202,7 +202,7 @@ class DidRegisterView(MyWallet, CreateView): icon = 'bi bi-patch-check-fill' wallet = True model = DID - fields = ('label',) + fields = ('label', 'type') success_url = reverse_lazy('idhub:user_dids') object = None diff --git a/idhub/views.py b/idhub/views.py index 5f6fb71..851011f 100644 --- a/idhub/views.py +++ b/idhub/views.py @@ -1,8 +1,12 @@ +from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.contrib.auth import views as auth_views from django.contrib.auth import login as auth_login -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, HttpResponse + +from idhub.models import DID +from trustchain_idhub import settings class LoginView(auth_views.LoginView): @@ -26,3 +30,12 @@ class LoginView(auth_views.LoginView): self.extra_context['success_url'] = admin_dashboard auth_login(self.request, user) return HttpResponseRedirect(self.extra_context['success_url']) + + +def serve_did(request, did_id): + id_did = f'did:web:{settings.DOMAIN}:did-registry:{did_id}' + did = get_object_or_404(DID, did=id_did) + document = did.didweb_document + retval = HttpResponse(document) + retval.headers["Content-Type"] = "application/json" + return retval diff --git a/idhub_auth/migrations/0001_initial.py b/idhub_auth/migrations/0001_initial.py index f460a62..dd15670 100644 --- a/idhub_auth/migrations/0001_initial.py +++ b/idhub_auth/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.5 on 2023-12-11 08:35 +# Generated by Django 4.2.5 on 2024-01-16 13:04 from django.db import migrations, models @@ -31,13 +31,23 @@ class Migration(migrations.Migration): ( 'email', models.EmailField( - max_length=255, unique=True, verbose_name='email address' + max_length=255, unique=True, verbose_name='Email address' ), ), ('is_active', models.BooleanField(default=True)), ('is_admin', models.BooleanField(default=False)), - ('first_name', models.CharField(blank=True, max_length=255, null=True)), - ('last_name', models.CharField(blank=True, max_length=255, null=True)), + ( + 'first_name', + models.CharField( + blank=True, max_length=255, null=True, verbose_name='First name' + ), + ), + ( + 'last_name', + models.CharField( + blank=True, max_length=255, null=True, verbose_name='Last name' + ), + ), ], options={ 'abstract': False, diff --git a/oidc4vp/migrations/0001_initial.py b/oidc4vp/migrations/0001_initial.py index 700c4e8..2b7618b 100644 --- a/oidc4vp/migrations/0001_initial.py +++ b/oidc4vp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.5 on 2023-12-11 08:35 +# Generated by Django 4.2.5 on 2024-01-16 13:04 from django.conf import settings from django.db import migrations, models @@ -30,7 +30,7 @@ class Migration(migrations.Migration): 'code', models.CharField(default=oidc4vp.models.set_code, max_length=24), ), - ('code_used', models.BooleanField()), + ('code_used', models.BooleanField(default=False)), ('created', models.DateTimeField(auto_now=True)), ('presentation_definition', models.CharField(max_length=250)), ], @@ -91,7 +91,7 @@ class Migration(migrations.Migration): models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, - related_name='oauth2vptoken', + related_name='vp_tokens', to='oidc4vp.authorization', ), ), diff --git a/promotion/migrations/0001_initial.py b/promotion/migrations/0001_initial.py index cbc1f17..85bdefd 100644 --- a/promotion/migrations/0001_initial.py +++ b/promotion/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.5 on 2023-12-11 08:35 +# Generated by Django 4.2.5 on 2024-01-16 13:04 from django.db import migrations, models import django.db.models.deletion diff --git a/utils/idhub_ssikit/__init__.py b/utils/idhub_ssikit/__init__.py index cc3e9b4..3521eba 100644 --- a/utils/idhub_ssikit/__init__.py +++ b/utils/idhub_ssikit/__init__.py @@ -6,6 +6,8 @@ import jinja2 from django.template.backends.django import Template from django.template.loader import get_template +from trustchain_idhub import settings + def generate_did_controller_key(): return didkit.generate_ed25519_key() @@ -15,6 +17,30 @@ 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 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:{settings.DOMAIN}:did-registry:{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 generate_generic_vc_id(): # TODO agree on a system for Verifiable Credential IDs return "https://pangea.org/credentials/42"