diff --git a/idhub/admin/forms.py b/idhub/admin/forms.py
index aa453ce..29ce073 100644
--- a/idhub/admin/forms.py
+++ b/idhub/admin/forms.py
@@ -1,23 +1,19 @@
-import csv
import json
-import copy
import base64
import jsonschema
import pandas as pd
-from pyhanko.sign import signers
-
+from nacl.exceptions import CryptoError
from django import forms
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
-from utils import credtools, certs
+from utils import certs
from idhub.models import (
DID,
File_datas,
Membership,
Schemas,
- Service,
UserRol,
VerificableCredential,
)
@@ -51,6 +47,38 @@ class TermsConditionsForm2(forms.Form):
return
+class EncryptionKeyForm(forms.Form):
+ key = forms.CharField(
+ label=_("Key for encrypt the secrets of all system"),
+ required=True
+ )
+
+ def clean(self):
+ data = self.cleaned_data
+ self._key = data["key"]
+ if not DID.objects.exists():
+ return data
+
+ did = DID.objects.first()
+ cache.set("KEY_DIDS", self._key, None)
+ try:
+ did.get_key_material()
+ except CryptoError:
+ cache.set("KEY_DIDS", None)
+ txt = _("Key no valid!")
+ raise ValidationError(txt)
+
+ cache.set("KEY_DIDS", None)
+ return data
+
+ def save(self, commit=True):
+
+ if commit:
+ cache.set("KEY_DIDS", self._key, None)
+
+ return
+
+
class TermsConditionsForm(forms.Form):
accept_privacy = forms.BooleanField(
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
@@ -133,7 +161,7 @@ class ImportForm(forms.Form):
self.fields['did'].choices = [
(x.did, x.label) for x in dids.filter(eidas1=False)
]
- self.fields['schema'].choices = [
+ self.fields['schema'].choices = [(0, _('Select one'))] + [
(x.id, x.name) for x in Schemas.objects.filter()
]
if dids.filter(eidas1=True).exists():
@@ -197,6 +225,9 @@ class ImportForm(forms.Form):
if not data_pd:
self.exception("This file is empty!")
+ if not self._schema:
+ return data
+
for n in range(df.last_valid_index()+1):
row = {}
for k in data_pd.keys():
@@ -226,18 +257,21 @@ class ImportForm(forms.Form):
except jsonschema.exceptions.ValidationError as err:
msg = "line {}: {}".format(line+1, err)
return self.exception(msg)
- # try:
- # check = credtools.validate_json(row, self.json_schema)
- # if check is not True:
- # raise ValidationError("Not valid row")
- # except Exception as e:
user, new = User.objects.get_or_create(email=row.get('email'))
if new:
self.users.append(user)
+ user.set_encrypted_sensitive_data()
+ user.save()
+ self.create_defaults_dids(user)
return user
+ def create_defaults_dids(self, user):
+ did = DID(label="Default", user=user, type=DID.Types.WEB)
+ did.set_did()
+ did.save()
+
def create_credential(self, user, row):
bcred = VerificableCredential.objects.filter(
user=user,
@@ -382,7 +416,6 @@ class ImportCertificateForm(forms.Form):
return data
def new_did(self):
- cert = self.pfx_file
keys = {
"cert": base64.b64encode(self.pfx_file).decode('utf-8'),
"passphrase": self._pss
@@ -397,8 +430,7 @@ class ImportCertificateForm(forms.Form):
type=DID.Types.KEY
)
- pw = cache.get("KEY_DIDS")
- self._did.set_key_material(key_material, pw)
+ self._did.set_key_material(key_material)
def save(self, commit=True):
diff --git a/idhub/admin/views.py b/idhub/admin/views.py
index 9eb204d..b5216a4 100644
--- a/idhub/admin/views.py
+++ b/idhub/admin/views.py
@@ -1,9 +1,6 @@
import os
import json
-import logging
-import pandas as pd
from pathlib import Path
-from jsonschema import validate
from smtplib import SMTPException
from django_tables2 import SingleTableView
@@ -18,22 +15,23 @@ from django.views.generic.edit import (
UpdateView,
)
from django.shortcuts import get_object_or_404, redirect
-from django.core.cache import cache
from django.urls import reverse_lazy
from django.http import HttpResponse
from django.contrib import messages
+from django.core.cache import cache
from utils import credtools
from idhub_auth.models import User
from idhub_auth.forms import ProfileForm
from idhub.mixins import AdminView, Http403
from idhub.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import (
+ EncryptionKeyForm,
+ ImportCertificateForm,
ImportForm,
MembershipForm,
TermsConditionsForm,
SchemaForm,
- UserRolForm,
- ImportCertificateForm,
+ UserRolForm
)
from idhub.admin.tables import (
DashboardTable,
@@ -79,7 +77,27 @@ class TermsAndConditionsView(AdminView, FormView):
return kwargs
def form_valid(self, form):
- user = form.save()
+ form.save()
+ return super().form_valid(form)
+
+
+class EncryptionKeyView(AdminView, FormView):
+ template_name = "idhub/admin/encryption_key.html"
+ title = _('Encryption Key')
+ section = ""
+ subtitle = _('Encryption Key')
+ icon = 'bi bi-key'
+ form_class = EncryptionKeyForm
+ success_url = reverse_lazy('idhub:admin_dashboard')
+
+ def get(self, request, *args, **kwargs):
+ if cache.get("KEY_DIDS"):
+ return redirect(self.success_url)
+
+ return super().get(request, *args, **kwargs)
+
+ def form_valid(self, form):
+ form.save()
return super().form_valid(form)
@@ -295,7 +313,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
return self.success_url
def form_valid(self, form):
- user = form.save()
+ super().form_valid(form)
+ user = form.instance
+ user.set_encrypted_sensitive_data()
+ user.save()
+ self.create_defaults_dids(user)
messages.success(self.request, _('The account was created successfully'))
Event.set_EV_USR_REGISTERED(user)
Event.set_EV_USR_WELCOME(user)
@@ -307,6 +329,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
messages.error(self.request, e)
return super().form_valid(form)
+ def create_defaults_dids(self, user):
+ did = DID(label="Default", user=user, type=DID.Types.WEB)
+ did.set_did()
+ did.save()
+
class PeopleMembershipRegisterView(People, FormView):
template_name = "idhub/admin/people_membership_register.html"
@@ -679,7 +706,7 @@ class CredentialJsonView(Credentials):
VerificableCredential,
pk=pk,
)
- response = HttpResponse(self.object.data, content_type="application/json")
+ response = HttpResponse(self.object.get_data(), content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
@@ -714,15 +741,10 @@ class DeleteCredentialsView(Credentials):
VerificableCredential,
pk=pk,
)
- status = [
- VerificableCredential.Status.REVOKED,
- VerificableCredential.Status.ISSUED
- ]
- if self.object.status in status:
- self.object.delete()
- messages.success(self.request, _('Credential deleted successfully'))
- Event.set_EV_CREDENTIAL_DELETED(self.object)
- Event.set_EV_CREDENTIAL_DELETED_BY_ADMIN(self.object)
+ self.object.delete()
+ messages.success(self.request, _('Credential deleted successfully'))
+ Event.set_EV_CREDENTIAL_DELETED(self.object)
+ Event.set_EV_CREDENTIAL_DELETED_BY_ADMIN(self.object)
return redirect(self.success_url)
@@ -760,7 +782,7 @@ class DidRegisterView(Credentials, CreateView):
def form_valid(self, form):
form.instance.user = self.request.user
- form.instance.set_did(cache.get("KEY_DIDS"))
+ form.instance.set_did()
form.save()
messages.success(self.request, _('DID created successfully'))
Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance)
@@ -782,7 +804,7 @@ class DidEditView(Credentials, UpdateView):
return super().get(request, *args, **kwargs)
def form_valid(self, form):
- user = form.save()
+ form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)
diff --git a/idhub/management/commands/initial_datas.py b/idhub/management/commands/initial_datas.py
index e8abf19..40cfa8b 100644
--- a/idhub/management/commands/initial_datas.py
+++ b/idhub/management/commands/initial_datas.py
@@ -5,13 +5,12 @@ import json
from pathlib import Path
from utils import credtools
from django.conf import settings
-from django.core.management.base import BaseCommand, CommandError
+from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.core.cache import cache
from decouple import config
from idhub.models import DID, Schemas
from oidc4vp.models import Organization
-from promotion.models import Promotion
User = get_user_model()
@@ -23,6 +22,8 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs):
ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org')
ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234')
+ KEY_DIDS = config('KEY_DIDS')
+ cache.set("KEY_DIDS", KEY_DIDS, None)
self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD)
if settings.CREATE_TEST_USERS:
@@ -43,21 +44,17 @@ class Command(BaseCommand):
def create_admin_users(self, email, password):
su = User.objects.create_superuser(email=email, password=password)
- su.set_encrypted_sensitive_data(password)
+ su.set_encrypted_sensitive_data()
su.save()
- key = su.decrypt_sensitive_data(password)
- key_dids = {su.id: key}
- cache.set("KEY_DIDS", key_dids, None)
- self.create_defaults_dids(su, key)
+ self.create_defaults_dids(su)
def create_users(self, email, password):
u = User.objects.create(email=email, password=password)
u.set_password(password)
- u.set_encrypted_sensitive_data(password)
+ u.set_encrypted_sensitive_data()
u.save()
- key = u.decrypt_sensitive_data(password)
- self.create_defaults_dids(u, key)
+ self.create_defaults_dids(u)
def create_organizations(self, name, url):
@@ -72,15 +69,14 @@ class Command(BaseCommand):
org1.my_client_secret = org2.client_secret
org1.save()
org2.save()
- def create_defaults_dids(self, u, password):
+
+ def create_defaults_dids(self, u):
did = DID(label="Default", user=u, type=DID.Types.WEB)
- did.set_did(password)
+ did.set_did()
did.save()
def create_schemas(self):
schemas_files = os.listdir(settings.SCHEMAS_DIR)
- schemas = [x for x in schemas_files
- if not Schemas.objects.filter(file_schema=x).exists()]
for x in schemas_files:
if Schemas.objects.filter(file_schema=x).exists():
continue
diff --git a/idhub/management/commands/send_mail_admins.py b/idhub/management/commands/send_mail_admins.py
new file mode 100644
index 0000000..0ef24f8
--- /dev/null
+++ b/idhub/management/commands/send_mail_admins.py
@@ -0,0 +1,56 @@
+import logging
+
+from urllib.parse import urlparse
+
+from django.conf import settings
+from django.template import loader
+from django.core.mail import EmailMultiAlternatives
+from django.core.management.base import BaseCommand
+from django.contrib.auth import get_user_model
+
+
+logger = logging.getLogger(__name__)
+User = get_user_model()
+
+
+class Command(BaseCommand):
+ help = "Send mails to the admins for add general key"
+ subject_template_name = 'idhub/admin/registration/start_app_admin_subject.txt'
+ email_template_name = 'idhub/admin/registration/start_app_admin_email.txt'
+ html_email_template_name = 'idhub/admin/registration/start_app_admin_email.html'
+
+ def handle(self, *args, **kwargs):
+ for user in User.objects.filter(is_admin=True):
+ self.send_email(user)
+
+ def send_email(self, user):
+ """
+ Send a email when a user is activated.
+ """
+ parsed_url = urlparse(settings.RESPONSE_URI)
+ domain = f"{parsed_url.scheme}://{parsed_url.netloc}/"
+ context = {
+ "domain": domain,
+ }
+ subject = loader.render_to_string(self.subject_template_name, context)
+ # Email subject *must not* contain newlines
+ subject = ''.join(subject.splitlines())
+ body = loader.render_to_string(self.email_template_name, context)
+ from_email = settings.DEFAULT_FROM_EMAIL
+ to_email = user.email
+
+ email_message = EmailMultiAlternatives(
+ subject, body, from_email, [to_email])
+ html_email = loader.render_to_string(self.html_email_template_name, context)
+ email_message.attach_alternative(html_email, 'text/html')
+ try:
+ if settings.ENABLE_EMAIL:
+ email_message.send()
+ return
+
+ logger.warning(to_email)
+ logger.warning(body)
+
+ except Exception as err:
+ logger.error(err)
+ return
diff --git a/idhub/mixins.py b/idhub/mixins.py
index b2b3fbe..6e793a8 100644
--- a/idhub/mixins.py
+++ b/idhub/mixins.py
@@ -1,6 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import gettext_lazy as _
-from django.contrib.auth import views as auth_views
from django.core.exceptions import PermissionDenied
from django.urls import reverse_lazy, resolve
from django.shortcuts import redirect
@@ -12,8 +11,8 @@ class Http403(PermissionDenied):
default_detail = _('Permission denied. User is not authenticated')
default_code = 'forbidden'
- def __init__(self, detail=None, code=None):
- if detail is not None:
+ def __init__(self, details=None, code=None):
+ if details is not None:
self.detail = details or self.default_details
if code is not None:
self.code = code or self.default_code
@@ -22,15 +21,30 @@ class Http403(PermissionDenied):
class UserView(LoginRequiredMixin):
login_url = "/login/"
wallet = False
+ admin_validated = False
path_terms = [
'admin_terms_and_conditions',
'user_terms_and_conditions',
'user_gdpr',
+ 'user_waiting',
+ 'user_waiting',
+ 'encryption_key',
]
def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS")
response = super().get(request, *args, **kwargs)
+
+ if not self.admin_validated:
+ actual_path = resolve(self.request.path).url_name
+ if not self.request.user.is_admin:
+ if actual_path != 'user_waiting':
+ return redirect(reverse_lazy("idhub:user_waiting"))
+
+ if self.request.user.is_admin:
+ if actual_path != 'encryption_key':
+ return redirect(reverse_lazy("idhub:encryption_key"))
+
url = self.check_gdpr()
return url or response
diff --git a/idhub/models.py b/idhub/models.py
index ae61c56..2f563bf 100644
--- a/idhub/models.py
+++ b/idhub/models.py
@@ -6,10 +6,8 @@ import datetime
from collections import OrderedDict
from django.db import models
from django.conf import settings
-from django.core.cache import cache
from django.template.loader import get_template
from django.utils.translation import gettext_lazy as _
-from nacl import secret
from utils.idhub_ssikit import (
generate_did_controller_key,
@@ -34,26 +32,27 @@ class Event(models.Model):
EV_DID_CREATED = 9, "DID created"
EV_DID_DELETED = 10, "DID deleted"
EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user"
- EV_CREDENTIAL_DELETED = 12, "Credential deleted"
- EV_CREDENTIAL_ISSUED_FOR_USER = 13, "Credential issued for user"
- EV_CREDENTIAL_ISSUED = 14, "Credential issued"
- EV_CREDENTIAL_PRESENTED_BY_USER = 15, "Credential presented by user"
- EV_CREDENTIAL_PRESENTED = 16, "Credential presented"
- EV_CREDENTIAL_ENABLED = 17, "Credential enabled"
- EV_CREDENTIAL_CAN_BE_REQUESTED = 18, "Credential available"
- EV_CREDENTIAL_REVOKED_BY_ADMIN = 19, "Credential revoked by admin"
- EV_CREDENTIAL_REVOKED = 20, "Credential revoked"
- EV_ROLE_CREATED_BY_ADMIN = 21, "Role created by admin"
- EV_ROLE_MODIFIED_BY_ADMIN = 22, "Role modified by admin"
- EV_ROLE_DELETED_BY_ADMIN = 23, "Role deleted by admin"
- EV_SERVICE_CREATED_BY_ADMIN = 24, "Service created by admin"
- EV_SERVICE_MODIFIED_BY_ADMIN = 25, "Service modified by admin"
- EV_SERVICE_DELETED_BY_ADMIN = 26, "Service deleted by admin"
- EV_ORG_DID_CREATED_BY_ADMIN = 27, "Organisational DID created by admin"
- EV_ORG_DID_DELETED_BY_ADMIN = 28, "Organisational DID deleted by admin"
- EV_USR_DEACTIVATED_BY_ADMIN = 29, "User deactivated"
- EV_USR_ACTIVATED_BY_ADMIN = 30, "User activated"
- EV_USR_SEND_VP = 31, "User send Verificable Presentation"
+ EV_CREDENTIAL_DELETED_BY_ADMIN = 12, "Credential deleted by admin"
+ EV_CREDENTIAL_DELETED = 13, "Credential deleted"
+ EV_CREDENTIAL_ISSUED_FOR_USER = 14, "Credential issued for user"
+ EV_CREDENTIAL_ISSUED = 15, "Credential issued"
+ EV_CREDENTIAL_PRESENTED_BY_USER = 16, "Credential presented by user"
+ EV_CREDENTIAL_PRESENTED = 17, "Credential presented"
+ EV_CREDENTIAL_ENABLED = 18, "Credential enabled"
+ EV_CREDENTIAL_CAN_BE_REQUESTED = 19, "Credential available"
+ EV_CREDENTIAL_REVOKED_BY_ADMIN = 20, "Credential revoked by admin"
+ EV_CREDENTIAL_REVOKED = 21, "Credential revoked"
+ EV_ROLE_CREATED_BY_ADMIN = 22, "Role created by admin"
+ EV_ROLE_MODIFIED_BY_ADMIN = 23, "Role modified by admin"
+ EV_ROLE_DELETED_BY_ADMIN = 24, "Role deleted by admin"
+ EV_SERVICE_CREATED_BY_ADMIN = 25, "Service created by admin"
+ EV_SERVICE_MODIFIED_BY_ADMIN = 26, "Service modified by admin"
+ EV_SERVICE_DELETED_BY_ADMIN = 27, "Service deleted by admin"
+ EV_ORG_DID_CREATED_BY_ADMIN = 28, "Organisational DID created by admin"
+ EV_ORG_DID_DELETED_BY_ADMIN = 29, "Organisational DID deleted by admin"
+ EV_USR_DEACTIVATED_BY_ADMIN = 30, "User deactivated"
+ EV_USR_ACTIVATED_BY_ADMIN = 31, "User activated"
+ EV_USR_SEND_VP = 32, "User send Verificable Presentation"
created = models.DateTimeField(_("Date"), auto_now=True)
message = models.CharField(_("Description"), max_length=350)
@@ -99,9 +98,8 @@ class Event(models.Model):
@classmethod
def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user):
msg = _("The user '{username}' has request the update of the following information: ")
- msg += "['field1':'value1', 'field2':'value2'>,...]".format(
- username=user.username,
- )
+ msg += "['field1':'value1', 'field2':'value2'>,...]"
+ msg = msg.format(username=user.username)
cls.objects.create(
type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER,
message=msg,
@@ -444,11 +442,11 @@ class DID(models.Model):
# JSON-serialized DID document
didweb_document = models.TextField()
- def get_key_material(self, password):
- return self.user.decrypt_data(self.key_material, password)
+ def get_key_material(self):
+ return self.user.decrypt_data(self.key_material)
- def set_key_material(self, value, password):
- self.key_material = self.user.encrypt_data(value, password)
+ def set_key_material(self, value):
+ self.key_material = self.user.encrypt_data(value)
@property
def is_organization_did(self):
@@ -456,9 +454,9 @@ class DID(models.Model):
return True
return False
- def set_did(self, password):
+ def set_did(self):
new_key_material = generate_did_controller_key()
- self.set_key_material(new_key_material, password)
+ self.set_key_material(new_key_material)
if self.type == self.Types.KEY:
self.did = keydid_from_controller_key(new_key_material)
@@ -621,17 +619,14 @@ class VerificableCredential(models.Model):
return True
return False
- def get_data(self, password):
+ def get_data(self):
if not self.data:
return ""
- if self.eidas1_did:
- return self.data
-
- return self.user.decrypt_data(self.data, password)
+ return self.user.decrypt_data(self.data)
- def set_data(self, value, password):
- self.data = self.user.encrypt_data(value, password)
+ def set_data(self, value):
+ self.data = self.user.encrypt_data(value)
def get_description(self):
return self.schema._description or ''
@@ -649,35 +644,28 @@ class VerificableCredential(models.Model):
return self.Status(self.status).label
def get_datas(self):
- data = json.loads(self.csv_data).items()
- return data
+ data = self.render()
+ credential_subject = ujson.loads(data).get("credentialSubject", {})
+ return credential_subject.items()
- def issue(self, did, password, domain=settings.DOMAIN.strip("/")):
+ def issue(self, did, domain=settings.DOMAIN.strip("/")):
if self.status == self.Status.ISSUED:
return
self.subject_did = did
self.issued_on = datetime.datetime.now().astimezone(pytz.utc)
- issuer_pass = cache.get("KEY_DIDS")
- # issuer_pass = self.user.decrypt_data(
- # cache.get("KEY_DIDS"),
- # settings.SECRET_KEY,
- # )
# hash of credential without sign
self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest()
data = sign_credential(
self.render(domain),
- self.issuer_did.get_key_material(issuer_pass)
+ self.issuer_did.get_key_material()
)
valid, reason = verify_credential(data)
if not valid:
return
- if self.eidas1_did:
- self.data = data
- else:
- self.data = self.user.encrypt_data(data, password)
+ self.data = self.user.encrypt_data(data)
self.status = self.Status.ISSUED
@@ -714,7 +702,7 @@ class VerificableCredential(models.Model):
context.update(d)
return context
- def render(self, domain):
+ def render(self, domain=""):
context = self.get_context(domain)
template_name = 'credentials/{}'.format(
self.schema.file_schema
diff --git a/idhub/templates/auth/login.html b/idhub/templates/auth/login.html
index 1a1775c..18abfd8 100644
--- a/idhub/templates/auth/login.html
+++ b/idhub/templates/auth/login.html
@@ -46,7 +46,7 @@
class="btn btn-primary form-control" id="submit-id-submit">
-
@@ -38,7 +35,7 @@
{% trans 'Issuance date' %}:
- {{ object.issuer_on|default_if_none:"" }}
+ {{ object.issued_on|default_if_none:"" }}
@@ -49,11 +46,13 @@
{{ object.get_status}}
+ {% if object.issued_on %}
+ {% endif %}
diff --git a/idhub/templates/idhub/admin/registration/start_app_admin_email.html b/idhub/templates/idhub/admin/registration/start_app_admin_email.html
new file mode 100644
index 0000000..15bd8ad
--- /dev/null
+++ b/idhub/templates/idhub/admin/registration/start_app_admin_email.html
@@ -0,0 +1,9 @@
+Hola, se ha reiniciado el servicio de Idhub: {{ domain }}
+
+no será plenamente funcional hasta que no introduzcas la contraseña de encriptacion del sistema.
+
+
+Por favor entra en la aplicacion como administrador y añade esta contraseña.
+
+
+Muchas gracias
diff --git a/idhub/templates/idhub/admin/registration/start_app_admin_email.txt b/idhub/templates/idhub/admin/registration/start_app_admin_email.txt
new file mode 100644
index 0000000..ba23523
--- /dev/null
+++ b/idhub/templates/idhub/admin/registration/start_app_admin_email.txt
@@ -0,0 +1,7 @@
+Hola, se ha reiniciado el servicio de Idhub: {{ domain }}
+no será plenamente funcional hasta que no introduzcas la contraseña de encriptacion del sistema.
+
+Por favor entra en la aplicacion como administrador y añade esta contraseña.
+
+Muchas gracias
+
diff --git a/idhub/templates/idhub/admin/registration/start_app_admin_subject.txt b/idhub/templates/idhub/admin/registration/start_app_admin_subject.txt
new file mode 100644
index 0000000..47a9ea7
--- /dev/null
+++ b/idhub/templates/idhub/admin/registration/start_app_admin_subject.txt
@@ -0,0 +1 @@
+Reinicio de IdHub
diff --git a/idhub/templates/idhub/user/credential.html b/idhub/templates/idhub/user/credential.html
index 1ee66a4..b78e81b 100644
--- a/idhub/templates/idhub/user/credential.html
+++ b/idhub/templates/idhub/user/credential.html
@@ -25,7 +25,7 @@
{% trans 'Issuance date' %}:
- {{ object.issuer_on|default_if_none:"" }}
+ {{ object.issued_on|default_if_none:"" }}
@@ -38,6 +38,7 @@
+ {% if object.issued_on %}
{% if object.eidas1_did and admin_validated %}
@@ -47,5 +48,6 @@
+ {% endif %}
{% endblock %}
diff --git a/idhub/templates/idhub/user/waiting.html b/idhub/templates/idhub/user/waiting.html
new file mode 100644
index 0000000..3813c96
--- /dev/null
+++ b/idhub/templates/idhub/user/waiting.html
@@ -0,0 +1,10 @@
+{% extends "idhub/base.html" %}
+{% load i18n %}
+
+{% block content %}
+
+
+ {{ subtitle }}
+
+{% trans 'Please contact the administrator to open the service.' %}
+{% endblock %}
diff --git a/idhub/tests/test_tables.py b/idhub/tests/test_tables.py
index 2a6b28b..3dfe181 100644
--- a/idhub/tests/test_tables.py
+++ b/idhub/tests/test_tables.py
@@ -6,6 +6,7 @@ from unittest.mock import MagicMock
from django.conf import settings
from django.test import TestCase
from django.urls import reverse
+from django.core.cache import cache
from django.core.exceptions import FieldError
from idhub_auth.models import User
@@ -15,6 +16,7 @@ from idhub.models import Event, Membership, Rol, UserRol, Service, Schemas
class AdminDashboardTableTest(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
self.admin_user = User.objects.create_superuser(
email='adminuser@example.org',
password='adminpass12')
@@ -75,6 +77,7 @@ class AdminDashboardTableTest(TestCase):
class UserTableTest(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
self.user1 = User.objects.create(email="user1@example.com")
self.user2 = User.objects.create(email="user2@example.com")
Membership.objects.create(user=self.user1,
@@ -106,6 +109,7 @@ class UserTableTest(TestCase):
class TemplateTableTest(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
self.table = TemplateTable(Schemas.objects.all())
self.create_schemas(amount=3)
diff --git a/idhub/tests/test_views.py b/idhub/tests/test_views.py
index a6c66f7..10e5b24 100644
--- a/idhub/tests/test_views.py
+++ b/idhub/tests/test_views.py
@@ -1,4 +1,5 @@
from django.test import TestCase, RequestFactory
+from django.core.cache import cache
from django.urls import reverse
from idhub_auth.models import User
@@ -9,6 +10,7 @@ from idhub.admin.views import PeopleListView
class AdminDashboardViewTest(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
self.user = User.objects.create_user(
email='normaluser@example.org',
password='testpass12',
@@ -99,6 +101,7 @@ class AdminDashboardViewTest(TestCase):
class PeopleListViewTest(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
# Set up a RequestFactory to create mock requests
self.factory = RequestFactory()
@@ -144,6 +147,7 @@ class PeopleListViewTest(TestCase):
class UserDashboardViewTests(TestCase):
def setUp(self):
+ cache.set("KEY_DIDS", '1234', None)
# Create test users
self.admin_user = User.objects.create_superuser('admin@example.org', 'password')
self.admin_user.accept_gdpr=True
diff --git a/idhub/urls.py b/idhub/urls.py
index 30338b3..d0230c9 100644
--- a/idhub/urls.py
+++ b/idhub/urls.py
@@ -88,6 +88,9 @@ urlpatterns = [
path('user/terms/', views_user.TermsAndConditionsView.as_view(),
name='user_terms_and_conditions'),
+ path('waiting/', views_user.WaitingView.as_view(),
+ name='user_waiting'),
+
# Admin
path('admin/dashboard/', views_admin.DashboardView.as_view(),
name='admin_dashboard'),
@@ -173,6 +176,7 @@ urlpatterns = [
name='admin_terms_and_conditions'),
path('admin/import/new', views_admin.ImportAddView.as_view(),
name='admin_import_add'),
+ path('admin/enc/', views_admin.EncryptionKeyView.as_view(), name='encryption_key'),
path('admin/auth/
', views_admin.DobleFactorAuthView.as_view(),
name='admin_2fauth'),
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),
diff --git a/idhub/user/forms.py b/idhub/user/forms.py
index 9561eb7..81c36a7 100644
--- a/idhub/user/forms.py
+++ b/idhub/user/forms.py
@@ -1,3 +1,5 @@
+import logging
+
from django import forms
from django.conf import settings
from django.utils.translation import gettext_lazy as _
@@ -6,6 +8,9 @@ from oidc4vp.models import Organization
from idhub_auth.models import User
+logger = logging.getLogger(__name__)
+
+
class ProfileForm(forms.ModelForm):
MANDATORY_FIELDS = ['first_name', 'last_name', 'email']
@@ -81,7 +86,6 @@ class RequestCredentialForm(forms.Form):
self.user = kwargs.pop('user', None)
self.lang = kwargs.pop('lang', None)
self._domain = kwargs.pop('domain', None)
- self.password = kwargs.pop('password', None)
super().__init__(*args, **kwargs)
self.fields['did'].choices = [
(x.did, x.label) for x in DID.objects.filter(user=self.user)
@@ -109,9 +113,9 @@ class RequestCredentialForm(forms.Form):
did = did[0]
cred = cred[0]
try:
- if self.password:
- cred.issue(did, self.password, domain=self._domain)
- except Exception:
+ cred.issue(did, domain=self._domain)
+ except Exception as err:
+ logger.error(err)
return
if commit:
diff --git a/idhub/user/views.py b/idhub/user/views.py
index 3e70336..4d07540 100644
--- a/idhub/user/views.py
+++ b/idhub/user/views.py
@@ -1,8 +1,6 @@
-import os
import json
import base64
import qrcode
-import logging
import datetime
import weasyprint
import qrcode.image.svg
@@ -23,6 +21,7 @@ from django.views.generic.edit import (
)
from django.views.generic.base import TemplateView
from django.shortcuts import get_object_or_404, redirect
+from django.core.cache import cache
from django.urls import reverse_lazy
from django.http import HttpResponse
from django.contrib import messages
@@ -34,10 +33,7 @@ from idhub.user.tables import (
DIDTable,
CredentialsTable
)
-from django.core.cache import cache
-from django.conf import settings
from idhub.user.forms import (
- ProfileForm,
RequestCredentialForm,
DemandAuthorizationForm,
TermsConditionsForm
@@ -176,10 +172,25 @@ class TermsAndConditionsView(UserView, FormView):
return kwargs
def form_valid(self, form):
- user = form.save()
+ form.save()
return super().form_valid(form)
+class WaitingView(UserView, TemplateView):
+ template_name = "idhub/user/waiting.html"
+ title = _("Comunication with admin")
+ subtitle = _('Service temporary close')
+ section = ""
+ icon = 'bi bi-file-earmark-medical'
+ success_url = reverse_lazy('idhub:user_dashboard')
+
+ def get(self, request, *args, **kwargs):
+ if cache.get("KEY_DIDS"):
+ return redirect(self.success_url)
+ return super().get(request, *args, **kwargs)
+
+
+
class CredentialView(MyWallet, TemplateView):
template_name = "idhub/user/credential.html"
subtitle = _('Credential')
@@ -209,7 +220,8 @@ class CredentialPdfView(MyWallet, TemplateView):
file_name = "certificate.pdf"
def get(self, request, *args, **kwargs):
- self.admin_validated = cache.get("KEY_DIDS")
+ if not cache.get("KEY_DIDS"):
+ return redirect(reverse_lazy('idhub:user_dashboard'))
pk = kwargs['pk']
self.user = self.request.user
self.object = get_object_or_404(
@@ -235,7 +247,7 @@ class CredentialPdfView(MyWallet, TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- this_folder = str(Path.cwd())
+ # this_folder = str(Path.cwd())
path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg"
img_signature = next(Path.cwd().glob(path_img_sig))
with open(img_signature, 'rb') as _f:
@@ -297,10 +309,9 @@ class CredentialPdfView(MyWallet, TemplateView):
def get_pfx_data(self):
did = self.object.eidas1_did
- pw = self.admin_validated
- if not did or not pw:
+ if not did:
return None, None
- key_material = json.loads(did.get_key_material(pw))
+ key_material = json.loads(did.get_key_material())
cert = key_material.get("cert")
passphrase = key_material.get("passphrase")
if cert and passphrase:
@@ -352,14 +363,7 @@ class CredentialJsonView(MyWallet, TemplateView):
pk=pk,
user=self.request.user
)
- pass_enc = self.request.session.get("key_did")
- data = ""
- if pass_enc:
- user_pass = self.request.user.decrypt_data(
- pass_enc,
- self.request.user.password+self.request.session._session_key
- )
- data = self.object.get_data(user_pass)
+ data = self.object.get_data()
response = HttpResponse(data, content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
@@ -374,7 +378,7 @@ class PublicCredentialJsonView(View):
hash=pk,
eidas1_did__isnull=False,
)
- response = HttpResponse(self.object.data, content_type="application/json")
+ response = HttpResponse(self.object.get_data(), content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
@@ -388,8 +392,8 @@ class CredentialsRequestView(MyWallet, FormView):
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
- if not self.admin_validated:
- return redirect(reverse_lazy('idhub:user_dashboard'))
+ if not cache.get("KEY_DIDS"):
+ return redirect(reverse_lazy('idhub:user_waiting'))
return response
def get_form_kwargs(self):
@@ -398,15 +402,6 @@ class CredentialsRequestView(MyWallet, FormView):
kwargs['lang'] = self.request.LANGUAGE_CODE
domain = "{}://{}".format(self.request.scheme, self.request.get_host())
kwargs['domain'] = domain
- pass_enc = self.request.session.get("key_did")
- if pass_enc:
- user_pass = self.request.user.decrypt_data(
- pass_enc,
- self.request.user.password+self.request.session._session_key
- )
- else:
- pass_enc = None
- kwargs['password'] = user_pass
return kwargs
def form_valid(self, form):
@@ -483,11 +478,7 @@ class DidRegisterView(MyWallet, CreateView):
def form_valid(self, form):
form.instance.user = self.request.user
- pw = self.request.user.decrypt_data(
- self.request.session.get("key_did"),
- self.request.user.password+self.request.session._session_key
- )
- form.instance.set_did(pw)
+ form.instance.set_did()
form.save()
messages.success(self.request, _('DID created successfully'))
@@ -511,7 +502,7 @@ class DidEditView(MyWallet, UpdateView):
return super().get(request, *args, **kwargs)
def form_valid(self, form):
- user = form.save()
+ form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)
diff --git a/idhub/views.py b/idhub/views.py
index 0d0ee68..d3da1b4 100644
--- a/idhub/views.py
+++ b/idhub/views.py
@@ -6,7 +6,6 @@ import zlib
import pyroaring
from django.conf import settings
-from django.core.cache import cache
from django.urls import reverse_lazy
from django.views.generic.base import TemplateView
from django.contrib.auth import views as auth_views
@@ -18,7 +17,6 @@ from django.http import HttpResponseRedirect, HttpResponse, Http404
from idhub.models import DID, VerificableCredential
from idhub.email.views import NotifyActivateUserByEmail
-from trustchain_idhub import settings
logger = logging.getLogger(__name__)
@@ -46,30 +44,20 @@ class LoginView(auth_views.LoginView):
def form_valid(self, form):
user = form.get_user()
- password = form.cleaned_data.get("password")
auth_login(self.request, user)
- sensitive_data_encryption_key = user.decrypt_sensitive_data(password)
+ if user.is_anonymous:
+ return redirect(reverse_lazy("idhub:login"))
- if not user.is_anonymous and user.is_admin:
- admin_dashboard = reverse_lazy('idhub:admin_dashboard')
- self.extra_context['success_url'] = admin_dashboard
- # encryption_key = user.encrypt_data(
- # sensitive_data_encryption_key,
- # settings.SECRET_KEY
- # )
- # cache.set("KEY_DIDS", encryption_key, None)
- cache.set("KEY_DIDS", sensitive_data_encryption_key, None)
+ if user.is_admin:
if settings.ENABLE_2FACTOR_AUTH:
self.request.session["2fauth"] = str(uuid.uuid4())
return redirect(reverse_lazy('idhub:confirm_send_2f'))
- self.request.session["key_did"] = user.encrypt_data(
- sensitive_data_encryption_key,
- user.password+self.request.session._session_key
- )
+ admin_dashboard = reverse_lazy('idhub:admin_dashboard')
+ self.extra_context['success_url'] = admin_dashboard
- return HttpResponseRedirect(self.extra_context['success_url'])
+ return redirect(self.extra_context['success_url'])
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
@@ -80,7 +68,6 @@ class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
password = form.cleaned_data.get("new_password1")
user = form.user
user.set_password(password)
- user.set_encrypted_sensitive_data(password)
user.save()
return HttpResponseRedirect(self.success_url)
diff --git a/idhub_auth/models.py b/idhub_auth/models.py
index ca4b422..49a6281 100644
--- a/idhub_auth/models.py
+++ b/idhub_auth/models.py
@@ -1,7 +1,7 @@
import nacl
import base64
-from nacl import pwhash
+from nacl import pwhash, secret
from django.db import models
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
@@ -95,21 +95,24 @@ class User(AbstractBaseUser):
roles.append(r.name)
return ", ".join(set(roles))
- def derive_key_from_password(self, password):
+ def derive_key_from_password(self, password=None):
+ if not password:
+ password = cache.get("KEY_DIDS").encode('utf-8')
+
kdf = pwhash.argon2i.kdf
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE
return kdf(
- nacl.secret.SecretBox.KEY_SIZE,
+ secret.SecretBox.KEY_SIZE,
password,
self.get_salt(),
opslimit=ops,
memlimit=mem
)
- def decrypt_sensitive_data(self, password, data=None):
- sb_key = self.derive_key_from_password(password.encode('utf-8'))
- sb = nacl.secret.SecretBox(sb_key)
+ def decrypt_sensitive_data(self, data=None):
+ sb_key = self.derive_key_from_password()
+ sb = secret.SecretBox(sb_key)
if not data:
data = self.get_encrypted_sensitive_data()
if not isinstance(data, bytes):
@@ -117,9 +120,9 @@ class User(AbstractBaseUser):
return sb.decrypt(data).decode('utf-8')
- def encrypt_sensitive_data(self, password, data):
- sb_key = self.derive_key_from_password(password.encode('utf-8'))
- sb = nacl.secret.SecretBox(sb_key)
+ def encrypt_sensitive_data(self, data):
+ sb_key = self.derive_key_from_password()
+ sb = secret.SecretBox(sb_key)
if not isinstance(data, bytes):
data = data.encode('utf-8')
@@ -134,32 +137,33 @@ class User(AbstractBaseUser):
def get_encrypted_sensitive_data(self):
return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8'))
- def set_encrypted_sensitive_data(self, password):
+ def set_encrypted_sensitive_data(self):
key = base64.b64encode(nacl.utils.random(64))
self.set_salt()
- key_crypted = self.encrypt_sensitive_data(password, key)
+ key_crypted = self.encrypt_sensitive_data(key)
self.encrypted_sensitive_data = key_crypted
- def encrypt_data(self, data, password):
- sb = self.get_secret_box(password)
+ def encrypt_data(self, data):
+ sb = self.get_secret_box()
value_enc = sb.encrypt(data.encode('utf-8'))
return base64.b64encode(value_enc).decode('utf-8')
- def decrypt_data(self, data, password):
- sb = self.get_secret_box(password)
+ def decrypt_data(self, data):
+ sb = self.get_secret_box()
value = base64.b64decode(data.encode('utf-8'))
return sb.decrypt(value).decode('utf-8')
- def get_secret_box(self, password):
- pw = base64.b64decode(password.encode('utf-8')*4)
- sb_key = self.derive_key_from_password(pw)
- return nacl.secret.SecretBox(sb_key)
+ def get_secret_box(self):
+ sb_key = self.derive_key_from_password()
+ return secret.SecretBox(sb_key)
- def change_password(self, old_password, new_password):
- sensitive_data = self.decrypt_sensitive_data(old_password)
- self.encrypted_sensitive_data = self.encrypt_sensitive_data(
- new_password,
- sensitive_data
- )
- self.set_password(new_password)
+ def change_password_key(self, new_password):
+ data = self.decrypt_sensitive_data()
+ sb_key = self.derive_key_from_password(new_password)
+ sb = secret.SecretBox(sb_key)
+ if not isinstance(data, bytes):
+ data = data.encode('utf-8')
+
+ encrypted_data = base64.b64encode(sb.encrypt(data)).decode('utf-8')
+ self.encrypted_sensitive_data = encrypted_data
diff --git a/oidc4vp/forms.py b/oidc4vp/forms.py
index 560531c..1c4b19a 100644
--- a/oidc4vp/forms.py
+++ b/oidc4vp/forms.py
@@ -1,14 +1,11 @@
import json
-import requests
from django import forms
-from django.conf import settings
from django.template.loader import get_template
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from utils.idhub_ssikit import create_verifiable_presentation
-from oidc4vp.models import Organization
from idhub.models import VerificableCredential
@@ -19,7 +16,6 @@ class AuthorizeForm(forms.Form):
self.user = kwargs.pop('user', None)
self.org = kwargs.pop('org', None)
self.code = kwargs.pop('code', None)
- self.pw = kwargs.pop('pw', None)
self.presentation_definition = kwargs.pop('presentation_definition', [])
self.subject_did = None
@@ -53,7 +49,6 @@ class AuthorizeForm(forms.Form):
cred = self.user.decrypt_data(
c.data,
- self.pw
)
self.subject_did = c.subject_did
self.list_credentials.append(cred)
@@ -85,5 +80,5 @@ class AuthorizeForm(forms.Form):
"verifiable_credential_list": vc_list
}
unsigned_vp = vp_template.render(context)
- key_material = did.get_key_material(self.pw)
+ key_material = did.get_key_material()
self.vp = create_verifiable_presentation(key_material, unsigned_vp)
diff --git a/oidc4vp/models.py b/oidc4vp/models.py
index 42b0d93..9a4a4d4 100644
--- a/oidc4vp/models.py
+++ b/oidc4vp/models.py
@@ -5,7 +5,6 @@ import secrets
from django.conf import settings
from django.http import QueryDict
from django.utils.translation import gettext_lazy as _
-from django.shortcuts import get_object_or_404
from idhub_auth.models import User
from django.db import models
from utils.idhub_ssikit import verify_presentation
diff --git a/oidc4vp/views.py b/oidc4vp/views.py
index 7161aed..fb869ce 100644
--- a/oidc4vp/views.py
+++ b/oidc4vp/views.py
@@ -16,7 +16,6 @@ from idhub.mixins import UserView
from idhub.models import Event
from oidc4vp.forms import AuthorizeForm
-from utils.idhub_ssikit import verify_presentation
class AuthorizeView(UserView, FormView):
@@ -39,16 +38,11 @@ class AuthorizeView(UserView, FormView):
kwargs['user'] = self.request.user
try:
vps = json.loads(self.request.GET.get('presentation_definition'))
- except:
+ except Exception:
vps = []
kwargs['presentation_definition'] = vps
kwargs["org"] = self.get_org()
kwargs["code"] = self.request.GET.get('code')
- enc_pw = self.request.session["key_did"]
- kwargs['pw'] = self.request.user.decrypt_data(
- enc_pw,
- self.request.user.password+self.request.session._session_key
- )
return kwargs
def get_form(self, form_class=None):
@@ -64,7 +58,7 @@ class AuthorizeView(UserView, FormView):
return redirect(self.success_url)
try:
authorization = authorization.json()
- except:
+ except Exception:
messages.error(self.request, _("Error sending credential!"))
return redirect(self.success_url)
@@ -148,7 +142,6 @@ class VerifyView(View):
if len(auth_data) == 2 and auth_data[0].lower() == 'basic':
decoded_auth = base64.b64decode(auth_data[1]).decode('utf-8')
client_id, client_secret = decoded_auth.split(':', 1)
- org_url = request.GET.get('demand_uri')
org = get_object_or_404(
Organization,
client_id=client_id,
diff --git a/trustchain_idhub/settings.py b/trustchain_idhub/settings.py
index 043054d..538fa63 100644
--- a/trustchain_idhub/settings.py
+++ b/trustchain_idhub/settings.py
@@ -212,13 +212,11 @@ LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
- "console": {"class": "logging.StreamHandler"},
+ "console": {"level": "DEBUG", "class": "logging.StreamHandler"},
},
- "loggers": {
- "django": {
- "handlers": ["console"],
- "level": "INFO",
- },
+ "root": {
+ "handlers": ["console"],
+ "level": "DEBUG",
}
}