Merge pull request 'encrypt2' (#145) from encrypt2 into release
Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/145
This commit is contained in:
commit
4f562162bf
|
@ -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):
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
56
idhub/management/commands/send_mail_admins.py
Normal file
56
idhub/management/commands/send_mail_admins.py
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
class="btn btn-primary form-control" id="submit-id-submit">
|
||||
</div>
|
||||
</form>
|
||||
<div id="login-footer" class="mt-3 d-none">
|
||||
<div id="login-footer" class="mt-3">
|
||||
<a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
33
idhub/templates/idhub/admin/encryption_key.html
Normal file
33
idhub/templates/idhub/admin/encryption_key.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "idhub/base_admin.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h3>
|
||||
<i class="{{ icon }}"></i>
|
||||
{{ subtitle }}
|
||||
</h3>
|
||||
{% load django_bootstrap5 %}
|
||||
<form role="form" method="post">
|
||||
{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
|
||||
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
|
||||
<div class="message">
|
||||
{% for field, error in form.errors.items %}
|
||||
{{ error }}<br />
|
||||
{% endfor %}
|
||||
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
{% bootstrap_form form %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions-no-box">
|
||||
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -12,11 +12,8 @@
|
|||
<div class="col text-end">
|
||||
{% if object.get_status == 'Issued' %}
|
||||
<a class="btn btn-yellow" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-revoke" href="javascript:void()">{% trans 'Revoke' %}</a>
|
||||
<a class="btn btn-orange" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-delete" href="javascript:void()">{% trans 'Delete' %}</a>
|
||||
{% endif %}
|
||||
{% if object.get_status == 'Revoked' %}
|
||||
<a class="btn btn-orange" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-delete" href="javascript:void()">{% trans 'Delete' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -38,7 +35,7 @@
|
|||
<strong>{% trans 'Issuance date' %}:</strong>
|
||||
</div>
|
||||
<div class="col bg-light text-secondary">
|
||||
{{ object.issuer_on|default_if_none:"" }}
|
||||
{{ object.issued_on|default_if_none:"" }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
|
@ -49,11 +46,13 @@
|
|||
{{ object.get_status}}
|
||||
</div>
|
||||
</div>
|
||||
{% if object.issued_on %}
|
||||
<div class="row mt-3">
|
||||
<div class="col text-center">
|
||||
<a class="btn btn-green-admin" href="{% url 'idhub:admin_credential_json' object.id %}">{% trans 'View in JSON format' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal Revoke -->
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
Hola, se ha reiniciado el servicio de Idhub: {{ domain }}
|
||||
<br />
|
||||
no será plenamente funcional hasta que no introduzcas la contraseña de encriptacion del sistema.
|
||||
<br />
|
||||
<br />
|
||||
Por favor entra en la aplicacion como administrador y añade esta contraseña.
|
||||
|
||||
<br />
|
||||
Muchas gracias
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
Reinicio de IdHub
|
|
@ -25,7 +25,7 @@
|
|||
<strong>{% trans 'Issuance date' %}:</strong>
|
||||
</div>
|
||||
<div class="col bg-light text-secondary">
|
||||
{{ object.issuer_on|default_if_none:"" }}
|
||||
{{ object.issued_on|default_if_none:"" }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
|
@ -38,6 +38,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if object.issued_on %}
|
||||
<div class="row mt-3">
|
||||
{% if object.eidas1_did and admin_validated %}
|
||||
<div class="col text-center">
|
||||
|
@ -47,5 +48,6 @@
|
|||
<div class="col text-center">
|
||||
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View credential in JSON format' %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
10
idhub/templates/idhub/user/waiting.html
Normal file
10
idhub/templates/idhub/user/waiting.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "idhub/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h3>
|
||||
<i class="{{ icon }}"></i>
|
||||
{{ subtitle }}
|
||||
</h3>
|
||||
{% trans 'Please contact the administrator to open the service.' %}
|
||||
{% endblock %}
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/<uuid:admin2fauth>', views_admin.DobleFactorAuthView.as_view(),
|
||||
name='admin_2fauth'),
|
||||
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue