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 json
|
||||||
import copy
|
|
||||||
import base64
|
import base64
|
||||||
import jsonschema
|
import jsonschema
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from pyhanko.sign import signers
|
from nacl.exceptions import CryptoError
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from utils import credtools, certs
|
from utils import certs
|
||||||
from idhub.models import (
|
from idhub.models import (
|
||||||
DID,
|
DID,
|
||||||
File_datas,
|
File_datas,
|
||||||
Membership,
|
Membership,
|
||||||
Schemas,
|
Schemas,
|
||||||
Service,
|
|
||||||
UserRol,
|
UserRol,
|
||||||
VerificableCredential,
|
VerificableCredential,
|
||||||
)
|
)
|
||||||
|
@ -51,6 +47,38 @@ class TermsConditionsForm2(forms.Form):
|
||||||
return
|
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):
|
class TermsConditionsForm(forms.Form):
|
||||||
accept_privacy = forms.BooleanField(
|
accept_privacy = forms.BooleanField(
|
||||||
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
|
||||||
|
@ -133,7 +161,7 @@ class ImportForm(forms.Form):
|
||||||
self.fields['did'].choices = [
|
self.fields['did'].choices = [
|
||||||
(x.did, x.label) for x in dids.filter(eidas1=False)
|
(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()
|
(x.id, x.name) for x in Schemas.objects.filter()
|
||||||
]
|
]
|
||||||
if dids.filter(eidas1=True).exists():
|
if dids.filter(eidas1=True).exists():
|
||||||
|
@ -197,6 +225,9 @@ class ImportForm(forms.Form):
|
||||||
if not data_pd:
|
if not data_pd:
|
||||||
self.exception("This file is empty!")
|
self.exception("This file is empty!")
|
||||||
|
|
||||||
|
if not self._schema:
|
||||||
|
return data
|
||||||
|
|
||||||
for n in range(df.last_valid_index()+1):
|
for n in range(df.last_valid_index()+1):
|
||||||
row = {}
|
row = {}
|
||||||
for k in data_pd.keys():
|
for k in data_pd.keys():
|
||||||
|
@ -226,18 +257,21 @@ class ImportForm(forms.Form):
|
||||||
except jsonschema.exceptions.ValidationError as err:
|
except jsonschema.exceptions.ValidationError as err:
|
||||||
msg = "line {}: {}".format(line+1, err)
|
msg = "line {}: {}".format(line+1, err)
|
||||||
return self.exception(msg)
|
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'))
|
user, new = User.objects.get_or_create(email=row.get('email'))
|
||||||
if new:
|
if new:
|
||||||
self.users.append(user)
|
self.users.append(user)
|
||||||
|
user.set_encrypted_sensitive_data()
|
||||||
|
user.save()
|
||||||
|
self.create_defaults_dids(user)
|
||||||
|
|
||||||
return 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):
|
def create_credential(self, user, row):
|
||||||
bcred = VerificableCredential.objects.filter(
|
bcred = VerificableCredential.objects.filter(
|
||||||
user=user,
|
user=user,
|
||||||
|
@ -382,7 +416,6 @@ class ImportCertificateForm(forms.Form):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def new_did(self):
|
def new_did(self):
|
||||||
cert = self.pfx_file
|
|
||||||
keys = {
|
keys = {
|
||||||
"cert": base64.b64encode(self.pfx_file).decode('utf-8'),
|
"cert": base64.b64encode(self.pfx_file).decode('utf-8'),
|
||||||
"passphrase": self._pss
|
"passphrase": self._pss
|
||||||
|
@ -397,8 +430,7 @@ class ImportCertificateForm(forms.Form):
|
||||||
type=DID.Types.KEY
|
type=DID.Types.KEY
|
||||||
)
|
)
|
||||||
|
|
||||||
pw = cache.get("KEY_DIDS")
|
self._did.set_key_material(key_material)
|
||||||
self._did.set_key_material(key_material, pw)
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import pandas as pd
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from jsonschema import validate
|
|
||||||
from smtplib import SMTPException
|
from smtplib import SMTPException
|
||||||
from django_tables2 import SingleTableView
|
from django_tables2 import SingleTableView
|
||||||
|
|
||||||
|
@ -18,22 +15,23 @@ from django.views.generic.edit import (
|
||||||
UpdateView,
|
UpdateView,
|
||||||
)
|
)
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.core.cache import cache
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.core.cache import cache
|
||||||
from utils import credtools
|
from utils import credtools
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User
|
||||||
from idhub_auth.forms import ProfileForm
|
from idhub_auth.forms import ProfileForm
|
||||||
from idhub.mixins import AdminView, Http403
|
from idhub.mixins import AdminView, Http403
|
||||||
from idhub.email.views import NotifyActivateUserByEmail
|
from idhub.email.views import NotifyActivateUserByEmail
|
||||||
from idhub.admin.forms import (
|
from idhub.admin.forms import (
|
||||||
|
EncryptionKeyForm,
|
||||||
|
ImportCertificateForm,
|
||||||
ImportForm,
|
ImportForm,
|
||||||
MembershipForm,
|
MembershipForm,
|
||||||
TermsConditionsForm,
|
TermsConditionsForm,
|
||||||
SchemaForm,
|
SchemaForm,
|
||||||
UserRolForm,
|
UserRolForm
|
||||||
ImportCertificateForm,
|
|
||||||
)
|
)
|
||||||
from idhub.admin.tables import (
|
from idhub.admin.tables import (
|
||||||
DashboardTable,
|
DashboardTable,
|
||||||
|
@ -79,7 +77,27 @@ class TermsAndConditionsView(AdminView, FormView):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
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)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
@ -295,7 +313,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
|
||||||
return self.success_url
|
return self.success_url
|
||||||
|
|
||||||
def form_valid(self, form):
|
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'))
|
messages.success(self.request, _('The account was created successfully'))
|
||||||
Event.set_EV_USR_REGISTERED(user)
|
Event.set_EV_USR_REGISTERED(user)
|
||||||
Event.set_EV_USR_WELCOME(user)
|
Event.set_EV_USR_WELCOME(user)
|
||||||
|
@ -307,6 +329,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
|
||||||
messages.error(self.request, e)
|
messages.error(self.request, e)
|
||||||
return super().form_valid(form)
|
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):
|
class PeopleMembershipRegisterView(People, FormView):
|
||||||
template_name = "idhub/admin/people_membership_register.html"
|
template_name = "idhub/admin/people_membership_register.html"
|
||||||
|
@ -679,7 +706,7 @@ class CredentialJsonView(Credentials):
|
||||||
VerificableCredential,
|
VerificableCredential,
|
||||||
pk=pk,
|
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")
|
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -714,15 +741,10 @@ class DeleteCredentialsView(Credentials):
|
||||||
VerificableCredential,
|
VerificableCredential,
|
||||||
pk=pk,
|
pk=pk,
|
||||||
)
|
)
|
||||||
status = [
|
self.object.delete()
|
||||||
VerificableCredential.Status.REVOKED,
|
messages.success(self.request, _('Credential deleted successfully'))
|
||||||
VerificableCredential.Status.ISSUED
|
Event.set_EV_CREDENTIAL_DELETED(self.object)
|
||||||
]
|
Event.set_EV_CREDENTIAL_DELETED_BY_ADMIN(self.object)
|
||||||
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)
|
|
||||||
|
|
||||||
return redirect(self.success_url)
|
return redirect(self.success_url)
|
||||||
|
|
||||||
|
@ -760,7 +782,7 @@ class DidRegisterView(Credentials, CreateView):
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.user = self.request.user
|
form.instance.user = self.request.user
|
||||||
form.instance.set_did(cache.get("KEY_DIDS"))
|
form.instance.set_did()
|
||||||
form.save()
|
form.save()
|
||||||
messages.success(self.request, _('DID created successfully'))
|
messages.success(self.request, _('DID created successfully'))
|
||||||
Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance)
|
Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance)
|
||||||
|
@ -782,7 +804,7 @@ class DidEditView(Credentials, UpdateView):
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.save()
|
form.save()
|
||||||
messages.success(self.request, _('DID updated successfully'))
|
messages.success(self.request, _('DID updated successfully'))
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,12 @@ import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from utils import credtools
|
from utils import credtools
|
||||||
from django.conf import settings
|
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.contrib.auth import get_user_model
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from decouple import config
|
from decouple import config
|
||||||
from idhub.models import DID, Schemas
|
from idhub.models import DID, Schemas
|
||||||
from oidc4vp.models import Organization
|
from oidc4vp.models import Organization
|
||||||
from promotion.models import Promotion
|
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
@ -23,6 +22,8 @@ class Command(BaseCommand):
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org')
|
ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org')
|
||||||
ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234')
|
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)
|
self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD)
|
||||||
if settings.CREATE_TEST_USERS:
|
if settings.CREATE_TEST_USERS:
|
||||||
|
@ -43,21 +44,17 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def create_admin_users(self, email, password):
|
def create_admin_users(self, email, password):
|
||||||
su = User.objects.create_superuser(email=email, password=password)
|
su = User.objects.create_superuser(email=email, password=password)
|
||||||
su.set_encrypted_sensitive_data(password)
|
su.set_encrypted_sensitive_data()
|
||||||
su.save()
|
su.save()
|
||||||
key = su.decrypt_sensitive_data(password)
|
self.create_defaults_dids(su)
|
||||||
key_dids = {su.id: key}
|
|
||||||
cache.set("KEY_DIDS", key_dids, None)
|
|
||||||
self.create_defaults_dids(su, key)
|
|
||||||
|
|
||||||
|
|
||||||
def create_users(self, email, password):
|
def create_users(self, email, password):
|
||||||
u = User.objects.create(email=email, password=password)
|
u = User.objects.create(email=email, password=password)
|
||||||
u.set_password(password)
|
u.set_password(password)
|
||||||
u.set_encrypted_sensitive_data(password)
|
u.set_encrypted_sensitive_data()
|
||||||
u.save()
|
u.save()
|
||||||
key = u.decrypt_sensitive_data(password)
|
self.create_defaults_dids(u)
|
||||||
self.create_defaults_dids(u, key)
|
|
||||||
|
|
||||||
|
|
||||||
def create_organizations(self, name, url):
|
def create_organizations(self, name, url):
|
||||||
|
@ -72,15 +69,14 @@ class Command(BaseCommand):
|
||||||
org1.my_client_secret = org2.client_secret
|
org1.my_client_secret = org2.client_secret
|
||||||
org1.save()
|
org1.save()
|
||||||
org2.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 = DID(label="Default", user=u, type=DID.Types.WEB)
|
||||||
did.set_did(password)
|
did.set_did()
|
||||||
did.save()
|
did.save()
|
||||||
|
|
||||||
def create_schemas(self):
|
def create_schemas(self):
|
||||||
schemas_files = os.listdir(settings.SCHEMAS_DIR)
|
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:
|
for x in schemas_files:
|
||||||
if Schemas.objects.filter(file_schema=x).exists():
|
if Schemas.objects.filter(file_schema=x).exists():
|
||||||
continue
|
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.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.translation import gettext_lazy as _
|
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.core.exceptions import PermissionDenied
|
||||||
from django.urls import reverse_lazy, resolve
|
from django.urls import reverse_lazy, resolve
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
@ -12,8 +11,8 @@ class Http403(PermissionDenied):
|
||||||
default_detail = _('Permission denied. User is not authenticated')
|
default_detail = _('Permission denied. User is not authenticated')
|
||||||
default_code = 'forbidden'
|
default_code = 'forbidden'
|
||||||
|
|
||||||
def __init__(self, detail=None, code=None):
|
def __init__(self, details=None, code=None):
|
||||||
if detail is not None:
|
if details is not None:
|
||||||
self.detail = details or self.default_details
|
self.detail = details or self.default_details
|
||||||
if code is not None:
|
if code is not None:
|
||||||
self.code = code or self.default_code
|
self.code = code or self.default_code
|
||||||
|
@ -22,15 +21,30 @@ class Http403(PermissionDenied):
|
||||||
class UserView(LoginRequiredMixin):
|
class UserView(LoginRequiredMixin):
|
||||||
login_url = "/login/"
|
login_url = "/login/"
|
||||||
wallet = False
|
wallet = False
|
||||||
|
admin_validated = False
|
||||||
path_terms = [
|
path_terms = [
|
||||||
'admin_terms_and_conditions',
|
'admin_terms_and_conditions',
|
||||||
'user_terms_and_conditions',
|
'user_terms_and_conditions',
|
||||||
'user_gdpr',
|
'user_gdpr',
|
||||||
|
'user_waiting',
|
||||||
|
'user_waiting',
|
||||||
|
'encryption_key',
|
||||||
]
|
]
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.admin_validated = cache.get("KEY_DIDS")
|
self.admin_validated = cache.get("KEY_DIDS")
|
||||||
response = super().get(request, *args, **kwargs)
|
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()
|
url = self.check_gdpr()
|
||||||
|
|
||||||
return url or response
|
return url or response
|
||||||
|
|
|
@ -6,10 +6,8 @@ import datetime
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from nacl import secret
|
|
||||||
|
|
||||||
from utils.idhub_ssikit import (
|
from utils.idhub_ssikit import (
|
||||||
generate_did_controller_key,
|
generate_did_controller_key,
|
||||||
|
@ -34,26 +32,27 @@ class Event(models.Model):
|
||||||
EV_DID_CREATED = 9, "DID created"
|
EV_DID_CREATED = 9, "DID created"
|
||||||
EV_DID_DELETED = 10, "DID deleted"
|
EV_DID_DELETED = 10, "DID deleted"
|
||||||
EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user"
|
EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user"
|
||||||
EV_CREDENTIAL_DELETED = 12, "Credential deleted"
|
EV_CREDENTIAL_DELETED_BY_ADMIN = 12, "Credential deleted by admin"
|
||||||
EV_CREDENTIAL_ISSUED_FOR_USER = 13, "Credential issued for user"
|
EV_CREDENTIAL_DELETED = 13, "Credential deleted"
|
||||||
EV_CREDENTIAL_ISSUED = 14, "Credential issued"
|
EV_CREDENTIAL_ISSUED_FOR_USER = 14, "Credential issued for user"
|
||||||
EV_CREDENTIAL_PRESENTED_BY_USER = 15, "Credential presented by user"
|
EV_CREDENTIAL_ISSUED = 15, "Credential issued"
|
||||||
EV_CREDENTIAL_PRESENTED = 16, "Credential presented"
|
EV_CREDENTIAL_PRESENTED_BY_USER = 16, "Credential presented by user"
|
||||||
EV_CREDENTIAL_ENABLED = 17, "Credential enabled"
|
EV_CREDENTIAL_PRESENTED = 17, "Credential presented"
|
||||||
EV_CREDENTIAL_CAN_BE_REQUESTED = 18, "Credential available"
|
EV_CREDENTIAL_ENABLED = 18, "Credential enabled"
|
||||||
EV_CREDENTIAL_REVOKED_BY_ADMIN = 19, "Credential revoked by admin"
|
EV_CREDENTIAL_CAN_BE_REQUESTED = 19, "Credential available"
|
||||||
EV_CREDENTIAL_REVOKED = 20, "Credential revoked"
|
EV_CREDENTIAL_REVOKED_BY_ADMIN = 20, "Credential revoked by admin"
|
||||||
EV_ROLE_CREATED_BY_ADMIN = 21, "Role created by admin"
|
EV_CREDENTIAL_REVOKED = 21, "Credential revoked"
|
||||||
EV_ROLE_MODIFIED_BY_ADMIN = 22, "Role modified by admin"
|
EV_ROLE_CREATED_BY_ADMIN = 22, "Role created by admin"
|
||||||
EV_ROLE_DELETED_BY_ADMIN = 23, "Role deleted by admin"
|
EV_ROLE_MODIFIED_BY_ADMIN = 23, "Role modified by admin"
|
||||||
EV_SERVICE_CREATED_BY_ADMIN = 24, "Service created by admin"
|
EV_ROLE_DELETED_BY_ADMIN = 24, "Role deleted by admin"
|
||||||
EV_SERVICE_MODIFIED_BY_ADMIN = 25, "Service modified by admin"
|
EV_SERVICE_CREATED_BY_ADMIN = 25, "Service created by admin"
|
||||||
EV_SERVICE_DELETED_BY_ADMIN = 26, "Service deleted by admin"
|
EV_SERVICE_MODIFIED_BY_ADMIN = 26, "Service modified by admin"
|
||||||
EV_ORG_DID_CREATED_BY_ADMIN = 27, "Organisational DID created by admin"
|
EV_SERVICE_DELETED_BY_ADMIN = 27, "Service deleted by admin"
|
||||||
EV_ORG_DID_DELETED_BY_ADMIN = 28, "Organisational DID deleted by admin"
|
EV_ORG_DID_CREATED_BY_ADMIN = 28, "Organisational DID created by admin"
|
||||||
EV_USR_DEACTIVATED_BY_ADMIN = 29, "User deactivated"
|
EV_ORG_DID_DELETED_BY_ADMIN = 29, "Organisational DID deleted by admin"
|
||||||
EV_USR_ACTIVATED_BY_ADMIN = 30, "User activated"
|
EV_USR_DEACTIVATED_BY_ADMIN = 30, "User deactivated"
|
||||||
EV_USR_SEND_VP = 31, "User send Verificable Presentation"
|
EV_USR_ACTIVATED_BY_ADMIN = 31, "User activated"
|
||||||
|
EV_USR_SEND_VP = 32, "User send Verificable Presentation"
|
||||||
|
|
||||||
created = models.DateTimeField(_("Date"), auto_now=True)
|
created = models.DateTimeField(_("Date"), auto_now=True)
|
||||||
message = models.CharField(_("Description"), max_length=350)
|
message = models.CharField(_("Description"), max_length=350)
|
||||||
|
@ -99,9 +98,8 @@ class Event(models.Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user):
|
def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user):
|
||||||
msg = _("The user '{username}' has request the update of the following information: ")
|
msg = _("The user '{username}' has request the update of the following information: ")
|
||||||
msg += "['field1':'value1', 'field2':'value2'>,...]".format(
|
msg += "['field1':'value1', 'field2':'value2'>,...]"
|
||||||
username=user.username,
|
msg = msg.format(username=user.username)
|
||||||
)
|
|
||||||
cls.objects.create(
|
cls.objects.create(
|
||||||
type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER,
|
type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER,
|
||||||
message=msg,
|
message=msg,
|
||||||
|
@ -444,11 +442,11 @@ class DID(models.Model):
|
||||||
# JSON-serialized DID document
|
# JSON-serialized DID document
|
||||||
didweb_document = models.TextField()
|
didweb_document = models.TextField()
|
||||||
|
|
||||||
def get_key_material(self, password):
|
def get_key_material(self):
|
||||||
return self.user.decrypt_data(self.key_material, password)
|
return self.user.decrypt_data(self.key_material)
|
||||||
|
|
||||||
def set_key_material(self, value, password):
|
def set_key_material(self, value):
|
||||||
self.key_material = self.user.encrypt_data(value, password)
|
self.key_material = self.user.encrypt_data(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_organization_did(self):
|
def is_organization_did(self):
|
||||||
|
@ -456,9 +454,9 @@ class DID(models.Model):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_did(self, password):
|
def set_did(self):
|
||||||
new_key_material = generate_did_controller_key()
|
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:
|
if self.type == self.Types.KEY:
|
||||||
self.did = keydid_from_controller_key(new_key_material)
|
self.did = keydid_from_controller_key(new_key_material)
|
||||||
|
@ -621,17 +619,14 @@ class VerificableCredential(models.Model):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_data(self, password):
|
def get_data(self):
|
||||||
if not self.data:
|
if not self.data:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
if self.eidas1_did:
|
return self.user.decrypt_data(self.data)
|
||||||
return self.data
|
|
||||||
|
|
||||||
return self.user.decrypt_data(self.data, password)
|
|
||||||
|
|
||||||
def set_data(self, value, password):
|
def set_data(self, value):
|
||||||
self.data = self.user.encrypt_data(value, password)
|
self.data = self.user.encrypt_data(value)
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return self.schema._description or ''
|
return self.schema._description or ''
|
||||||
|
@ -649,35 +644,28 @@ class VerificableCredential(models.Model):
|
||||||
return self.Status(self.status).label
|
return self.Status(self.status).label
|
||||||
|
|
||||||
def get_datas(self):
|
def get_datas(self):
|
||||||
data = json.loads(self.csv_data).items()
|
data = self.render()
|
||||||
return data
|
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:
|
if self.status == self.Status.ISSUED:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.subject_did = did
|
self.subject_did = did
|
||||||
self.issued_on = datetime.datetime.now().astimezone(pytz.utc)
|
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
|
# hash of credential without sign
|
||||||
self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest()
|
self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest()
|
||||||
data = sign_credential(
|
data = sign_credential(
|
||||||
self.render(domain),
|
self.render(domain),
|
||||||
self.issuer_did.get_key_material(issuer_pass)
|
self.issuer_did.get_key_material()
|
||||||
)
|
)
|
||||||
valid, reason = verify_credential(data)
|
valid, reason = verify_credential(data)
|
||||||
if not valid:
|
if not valid:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.eidas1_did:
|
self.data = self.user.encrypt_data(data)
|
||||||
self.data = data
|
|
||||||
else:
|
|
||||||
self.data = self.user.encrypt_data(data, password)
|
|
||||||
|
|
||||||
self.status = self.Status.ISSUED
|
self.status = self.Status.ISSUED
|
||||||
|
|
||||||
|
@ -714,7 +702,7 @@ class VerificableCredential(models.Model):
|
||||||
context.update(d)
|
context.update(d)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def render(self, domain):
|
def render(self, domain=""):
|
||||||
context = self.get_context(domain)
|
context = self.get_context(domain)
|
||||||
template_name = 'credentials/{}'.format(
|
template_name = 'credentials/{}'.format(
|
||||||
self.schema.file_schema
|
self.schema.file_schema
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
class="btn btn-primary form-control" id="submit-id-submit">
|
class="btn btn-primary form-control" id="submit-id-submit">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</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>
|
<a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% 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">
|
<div class="col text-end">
|
||||||
{% if object.get_status == 'Issued' %}
|
{% 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-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 %}
|
{% 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>
|
<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>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -38,7 +35,7 @@
|
||||||
<strong>{% trans 'Issuance date' %}:</strong>
|
<strong>{% trans 'Issuance date' %}:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="col bg-light text-secondary">
|
<div class="col bg-light text-secondary">
|
||||||
{{ object.issuer_on|default_if_none:"" }}
|
{{ object.issued_on|default_if_none:"" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
|
@ -49,11 +46,13 @@
|
||||||
{{ object.get_status}}
|
{{ object.get_status}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if object.issued_on %}
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
<div class="col text-center">
|
<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>
|
<a class="btn btn-green-admin" href="{% url 'idhub:admin_credential_json' object.id %}">{% trans 'View in JSON format' %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Modal Revoke -->
|
<!-- 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>
|
<strong>{% trans 'Issuance date' %}:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="col bg-light text-secondary">
|
<div class="col bg-light text-secondary">
|
||||||
{{ object.issuer_on|default_if_none:"" }}
|
{{ object.issued_on|default_if_none:"" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if object.issued_on %}
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
{% if object.eidas1_did and admin_validated %}
|
{% if object.eidas1_did and admin_validated %}
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
|
@ -47,5 +48,6 @@
|
||||||
<div class="col text-center">
|
<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>
|
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View credential in JSON format' %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% 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.conf import settings
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.core.cache import cache
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
|
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User
|
||||||
|
@ -15,6 +16,7 @@ from idhub.models import Event, Membership, Rol, UserRol, Service, Schemas
|
||||||
|
|
||||||
class AdminDashboardTableTest(TestCase):
|
class AdminDashboardTableTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
self.admin_user = User.objects.create_superuser(
|
self.admin_user = User.objects.create_superuser(
|
||||||
email='adminuser@example.org',
|
email='adminuser@example.org',
|
||||||
password='adminpass12')
|
password='adminpass12')
|
||||||
|
@ -75,6 +77,7 @@ class AdminDashboardTableTest(TestCase):
|
||||||
class UserTableTest(TestCase):
|
class UserTableTest(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
self.user1 = User.objects.create(email="user1@example.com")
|
self.user1 = User.objects.create(email="user1@example.com")
|
||||||
self.user2 = User.objects.create(email="user2@example.com")
|
self.user2 = User.objects.create(email="user2@example.com")
|
||||||
Membership.objects.create(user=self.user1,
|
Membership.objects.create(user=self.user1,
|
||||||
|
@ -106,6 +109,7 @@ class UserTableTest(TestCase):
|
||||||
class TemplateTableTest(TestCase):
|
class TemplateTableTest(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
self.table = TemplateTable(Schemas.objects.all())
|
self.table = TemplateTable(Schemas.objects.all())
|
||||||
self.create_schemas(amount=3)
|
self.create_schemas(amount=3)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
|
from django.core.cache import cache
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User
|
||||||
|
@ -9,6 +10,7 @@ from idhub.admin.views import PeopleListView
|
||||||
class AdminDashboardViewTest(TestCase):
|
class AdminDashboardViewTest(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
self.user = User.objects.create_user(
|
self.user = User.objects.create_user(
|
||||||
email='normaluser@example.org',
|
email='normaluser@example.org',
|
||||||
password='testpass12',
|
password='testpass12',
|
||||||
|
@ -99,6 +101,7 @@ class AdminDashboardViewTest(TestCase):
|
||||||
class PeopleListViewTest(TestCase):
|
class PeopleListViewTest(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
# Set up a RequestFactory to create mock requests
|
# Set up a RequestFactory to create mock requests
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
|
@ -144,6 +147,7 @@ class PeopleListViewTest(TestCase):
|
||||||
|
|
||||||
class UserDashboardViewTests(TestCase):
|
class UserDashboardViewTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
cache.set("KEY_DIDS", '1234', None)
|
||||||
# Create test users
|
# Create test users
|
||||||
self.admin_user = User.objects.create_superuser('admin@example.org', 'password')
|
self.admin_user = User.objects.create_superuser('admin@example.org', 'password')
|
||||||
self.admin_user.accept_gdpr=True
|
self.admin_user.accept_gdpr=True
|
||||||
|
|
|
@ -88,6 +88,9 @@ urlpatterns = [
|
||||||
path('user/terms/', views_user.TermsAndConditionsView.as_view(),
|
path('user/terms/', views_user.TermsAndConditionsView.as_view(),
|
||||||
name='user_terms_and_conditions'),
|
name='user_terms_and_conditions'),
|
||||||
|
|
||||||
|
path('waiting/', views_user.WaitingView.as_view(),
|
||||||
|
name='user_waiting'),
|
||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
path('admin/dashboard/', views_admin.DashboardView.as_view(),
|
path('admin/dashboard/', views_admin.DashboardView.as_view(),
|
||||||
name='admin_dashboard'),
|
name='admin_dashboard'),
|
||||||
|
@ -173,6 +176,7 @@ urlpatterns = [
|
||||||
name='admin_terms_and_conditions'),
|
name='admin_terms_and_conditions'),
|
||||||
path('admin/import/new', views_admin.ImportAddView.as_view(),
|
path('admin/import/new', views_admin.ImportAddView.as_view(),
|
||||||
name='admin_import_add'),
|
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(),
|
path('admin/auth/<uuid:admin2fauth>', views_admin.DobleFactorAuthView.as_view(),
|
||||||
name='admin_2fauth'),
|
name='admin_2fauth'),
|
||||||
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),
|
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -6,6 +8,9 @@ from oidc4vp.models import Organization
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
MANDATORY_FIELDS = ['first_name', 'last_name', 'email']
|
MANDATORY_FIELDS = ['first_name', 'last_name', 'email']
|
||||||
|
|
||||||
|
@ -81,7 +86,6 @@ class RequestCredentialForm(forms.Form):
|
||||||
self.user = kwargs.pop('user', None)
|
self.user = kwargs.pop('user', None)
|
||||||
self.lang = kwargs.pop('lang', None)
|
self.lang = kwargs.pop('lang', None)
|
||||||
self._domain = kwargs.pop('domain', None)
|
self._domain = kwargs.pop('domain', None)
|
||||||
self.password = kwargs.pop('password', None)
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields['did'].choices = [
|
self.fields['did'].choices = [
|
||||||
(x.did, x.label) for x in DID.objects.filter(user=self.user)
|
(x.did, x.label) for x in DID.objects.filter(user=self.user)
|
||||||
|
@ -109,9 +113,9 @@ class RequestCredentialForm(forms.Form):
|
||||||
did = did[0]
|
did = did[0]
|
||||||
cred = cred[0]
|
cred = cred[0]
|
||||||
try:
|
try:
|
||||||
if self.password:
|
cred.issue(did, domain=self._domain)
|
||||||
cred.issue(did, self.password, domain=self._domain)
|
except Exception as err:
|
||||||
except Exception:
|
logger.error(err)
|
||||||
return
|
return
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
import qrcode
|
import qrcode
|
||||||
import logging
|
|
||||||
import datetime
|
import datetime
|
||||||
import weasyprint
|
import weasyprint
|
||||||
import qrcode.image.svg
|
import qrcode.image.svg
|
||||||
|
@ -23,6 +21,7 @@ from django.views.generic.edit import (
|
||||||
)
|
)
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
from django.core.cache import cache
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
@ -34,10 +33,7 @@ from idhub.user.tables import (
|
||||||
DIDTable,
|
DIDTable,
|
||||||
CredentialsTable
|
CredentialsTable
|
||||||
)
|
)
|
||||||
from django.core.cache import cache
|
|
||||||
from django.conf import settings
|
|
||||||
from idhub.user.forms import (
|
from idhub.user.forms import (
|
||||||
ProfileForm,
|
|
||||||
RequestCredentialForm,
|
RequestCredentialForm,
|
||||||
DemandAuthorizationForm,
|
DemandAuthorizationForm,
|
||||||
TermsConditionsForm
|
TermsConditionsForm
|
||||||
|
@ -176,10 +172,25 @@ class TermsAndConditionsView(UserView, FormView):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.save()
|
form.save()
|
||||||
return super().form_valid(form)
|
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):
|
class CredentialView(MyWallet, TemplateView):
|
||||||
template_name = "idhub/user/credential.html"
|
template_name = "idhub/user/credential.html"
|
||||||
subtitle = _('Credential')
|
subtitle = _('Credential')
|
||||||
|
@ -209,7 +220,8 @@ class CredentialPdfView(MyWallet, TemplateView):
|
||||||
file_name = "certificate.pdf"
|
file_name = "certificate.pdf"
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
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']
|
pk = kwargs['pk']
|
||||||
self.user = self.request.user
|
self.user = self.request.user
|
||||||
self.object = get_object_or_404(
|
self.object = get_object_or_404(
|
||||||
|
@ -235,7 +247,7 @@ class CredentialPdfView(MyWallet, TemplateView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**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"
|
path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg"
|
||||||
img_signature = next(Path.cwd().glob(path_img_sig))
|
img_signature = next(Path.cwd().glob(path_img_sig))
|
||||||
with open(img_signature, 'rb') as _f:
|
with open(img_signature, 'rb') as _f:
|
||||||
|
@ -297,10 +309,9 @@ class CredentialPdfView(MyWallet, TemplateView):
|
||||||
|
|
||||||
def get_pfx_data(self):
|
def get_pfx_data(self):
|
||||||
did = self.object.eidas1_did
|
did = self.object.eidas1_did
|
||||||
pw = self.admin_validated
|
if not did:
|
||||||
if not did or not pw:
|
|
||||||
return None, None
|
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")
|
cert = key_material.get("cert")
|
||||||
passphrase = key_material.get("passphrase")
|
passphrase = key_material.get("passphrase")
|
||||||
if cert and passphrase:
|
if cert and passphrase:
|
||||||
|
@ -352,14 +363,7 @@ class CredentialJsonView(MyWallet, TemplateView):
|
||||||
pk=pk,
|
pk=pk,
|
||||||
user=self.request.user
|
user=self.request.user
|
||||||
)
|
)
|
||||||
pass_enc = self.request.session.get("key_did")
|
data = self.object.get_data()
|
||||||
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)
|
|
||||||
response = HttpResponse(data, content_type="application/json")
|
response = HttpResponse(data, content_type="application/json")
|
||||||
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
|
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
|
||||||
return response
|
return response
|
||||||
|
@ -374,7 +378,7 @@ class PublicCredentialJsonView(View):
|
||||||
hash=pk,
|
hash=pk,
|
||||||
eidas1_did__isnull=False,
|
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")
|
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -388,8 +392,8 @@ class CredentialsRequestView(MyWallet, FormView):
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
response = super().get(request, *args, **kwargs)
|
response = super().get(request, *args, **kwargs)
|
||||||
if not self.admin_validated:
|
if not cache.get("KEY_DIDS"):
|
||||||
return redirect(reverse_lazy('idhub:user_dashboard'))
|
return redirect(reverse_lazy('idhub:user_waiting'))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
|
@ -398,15 +402,6 @@ class CredentialsRequestView(MyWallet, FormView):
|
||||||
kwargs['lang'] = self.request.LANGUAGE_CODE
|
kwargs['lang'] = self.request.LANGUAGE_CODE
|
||||||
domain = "{}://{}".format(self.request.scheme, self.request.get_host())
|
domain = "{}://{}".format(self.request.scheme, self.request.get_host())
|
||||||
kwargs['domain'] = domain
|
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
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -483,11 +478,7 @@ class DidRegisterView(MyWallet, CreateView):
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.user = self.request.user
|
form.instance.user = self.request.user
|
||||||
pw = self.request.user.decrypt_data(
|
form.instance.set_did()
|
||||||
self.request.session.get("key_did"),
|
|
||||||
self.request.user.password+self.request.session._session_key
|
|
||||||
)
|
|
||||||
form.instance.set_did(pw)
|
|
||||||
form.save()
|
form.save()
|
||||||
messages.success(self.request, _('DID created successfully'))
|
messages.success(self.request, _('DID created successfully'))
|
||||||
|
|
||||||
|
@ -511,7 +502,7 @@ class DidEditView(MyWallet, UpdateView):
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.save()
|
form.save()
|
||||||
messages.success(self.request, _('DID updated successfully'))
|
messages.success(self.request, _('DID updated successfully'))
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import zlib
|
||||||
|
|
||||||
import pyroaring
|
import pyroaring
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.contrib.auth import views as auth_views
|
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.models import DID, VerificableCredential
|
||||||
from idhub.email.views import NotifyActivateUserByEmail
|
from idhub.email.views import NotifyActivateUserByEmail
|
||||||
from trustchain_idhub import settings
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -46,30 +44,20 @@ class LoginView(auth_views.LoginView):
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.get_user()
|
user = form.get_user()
|
||||||
password = form.cleaned_data.get("password")
|
|
||||||
auth_login(self.request, user)
|
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:
|
if 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 settings.ENABLE_2FACTOR_AUTH:
|
if settings.ENABLE_2FACTOR_AUTH:
|
||||||
self.request.session["2fauth"] = str(uuid.uuid4())
|
self.request.session["2fauth"] = str(uuid.uuid4())
|
||||||
return redirect(reverse_lazy('idhub:confirm_send_2f'))
|
return redirect(reverse_lazy('idhub:confirm_send_2f'))
|
||||||
|
|
||||||
self.request.session["key_did"] = user.encrypt_data(
|
admin_dashboard = reverse_lazy('idhub:admin_dashboard')
|
||||||
sensitive_data_encryption_key,
|
self.extra_context['success_url'] = admin_dashboard
|
||||||
user.password+self.request.session._session_key
|
|
||||||
)
|
|
||||||
|
|
||||||
return HttpResponseRedirect(self.extra_context['success_url'])
|
return redirect(self.extra_context['success_url'])
|
||||||
|
|
||||||
|
|
||||||
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
||||||
|
@ -80,7 +68,6 @@ class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
||||||
password = form.cleaned_data.get("new_password1")
|
password = form.cleaned_data.get("new_password1")
|
||||||
user = form.user
|
user = form.user
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.set_encrypted_sensitive_data(password)
|
|
||||||
user.save()
|
user.save()
|
||||||
return HttpResponseRedirect(self.success_url)
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import nacl
|
import nacl
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from nacl import pwhash
|
from nacl import pwhash, secret
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -95,21 +95,24 @@ class User(AbstractBaseUser):
|
||||||
roles.append(r.name)
|
roles.append(r.name)
|
||||||
return ", ".join(set(roles))
|
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
|
kdf = pwhash.argon2i.kdf
|
||||||
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE
|
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE
|
||||||
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE
|
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE
|
||||||
return kdf(
|
return kdf(
|
||||||
nacl.secret.SecretBox.KEY_SIZE,
|
secret.SecretBox.KEY_SIZE,
|
||||||
password,
|
password,
|
||||||
self.get_salt(),
|
self.get_salt(),
|
||||||
opslimit=ops,
|
opslimit=ops,
|
||||||
memlimit=mem
|
memlimit=mem
|
||||||
)
|
)
|
||||||
|
|
||||||
def decrypt_sensitive_data(self, password, data=None):
|
def decrypt_sensitive_data(self, data=None):
|
||||||
sb_key = self.derive_key_from_password(password.encode('utf-8'))
|
sb_key = self.derive_key_from_password()
|
||||||
sb = nacl.secret.SecretBox(sb_key)
|
sb = secret.SecretBox(sb_key)
|
||||||
if not data:
|
if not data:
|
||||||
data = self.get_encrypted_sensitive_data()
|
data = self.get_encrypted_sensitive_data()
|
||||||
if not isinstance(data, bytes):
|
if not isinstance(data, bytes):
|
||||||
|
@ -117,9 +120,9 @@ class User(AbstractBaseUser):
|
||||||
|
|
||||||
return sb.decrypt(data).decode('utf-8')
|
return sb.decrypt(data).decode('utf-8')
|
||||||
|
|
||||||
def encrypt_sensitive_data(self, password, data):
|
def encrypt_sensitive_data(self, data):
|
||||||
sb_key = self.derive_key_from_password(password.encode('utf-8'))
|
sb_key = self.derive_key_from_password()
|
||||||
sb = nacl.secret.SecretBox(sb_key)
|
sb = secret.SecretBox(sb_key)
|
||||||
if not isinstance(data, bytes):
|
if not isinstance(data, bytes):
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
|
|
||||||
|
@ -134,32 +137,33 @@ class User(AbstractBaseUser):
|
||||||
def get_encrypted_sensitive_data(self):
|
def get_encrypted_sensitive_data(self):
|
||||||
return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8'))
|
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))
|
key = base64.b64encode(nacl.utils.random(64))
|
||||||
self.set_salt()
|
self.set_salt()
|
||||||
|
|
||||||
key_crypted = self.encrypt_sensitive_data(password, key)
|
key_crypted = self.encrypt_sensitive_data(key)
|
||||||
self.encrypted_sensitive_data = key_crypted
|
self.encrypted_sensitive_data = key_crypted
|
||||||
|
|
||||||
def encrypt_data(self, data, password):
|
def encrypt_data(self, data):
|
||||||
sb = self.get_secret_box(password)
|
sb = self.get_secret_box()
|
||||||
value_enc = sb.encrypt(data.encode('utf-8'))
|
value_enc = sb.encrypt(data.encode('utf-8'))
|
||||||
return base64.b64encode(value_enc).decode('utf-8')
|
return base64.b64encode(value_enc).decode('utf-8')
|
||||||
|
|
||||||
def decrypt_data(self, data, password):
|
def decrypt_data(self, data):
|
||||||
sb = self.get_secret_box(password)
|
sb = self.get_secret_box()
|
||||||
value = base64.b64decode(data.encode('utf-8'))
|
value = base64.b64decode(data.encode('utf-8'))
|
||||||
return sb.decrypt(value).decode('utf-8')
|
return sb.decrypt(value).decode('utf-8')
|
||||||
|
|
||||||
def get_secret_box(self, password):
|
def get_secret_box(self):
|
||||||
pw = base64.b64decode(password.encode('utf-8')*4)
|
sb_key = self.derive_key_from_password()
|
||||||
sb_key = self.derive_key_from_password(pw)
|
return secret.SecretBox(sb_key)
|
||||||
return nacl.secret.SecretBox(sb_key)
|
|
||||||
|
|
||||||
def change_password(self, old_password, new_password):
|
def change_password_key(self, new_password):
|
||||||
sensitive_data = self.decrypt_sensitive_data(old_password)
|
data = self.decrypt_sensitive_data()
|
||||||
self.encrypted_sensitive_data = self.encrypt_sensitive_data(
|
sb_key = self.derive_key_from_password(new_password)
|
||||||
new_password,
|
sb = secret.SecretBox(sb_key)
|
||||||
sensitive_data
|
if not isinstance(data, bytes):
|
||||||
)
|
data = data.encode('utf-8')
|
||||||
self.set_password(new_password)
|
|
||||||
|
encrypted_data = base64.b64encode(sb.encrypt(data)).decode('utf-8')
|
||||||
|
self.encrypted_sensitive_data = encrypted_data
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import json
|
import json
|
||||||
import requests
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from utils.idhub_ssikit import create_verifiable_presentation
|
from utils.idhub_ssikit import create_verifiable_presentation
|
||||||
from oidc4vp.models import Organization
|
|
||||||
from idhub.models import VerificableCredential
|
from idhub.models import VerificableCredential
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +16,6 @@ class AuthorizeForm(forms.Form):
|
||||||
self.user = kwargs.pop('user', None)
|
self.user = kwargs.pop('user', None)
|
||||||
self.org = kwargs.pop('org', None)
|
self.org = kwargs.pop('org', None)
|
||||||
self.code = kwargs.pop('code', None)
|
self.code = kwargs.pop('code', None)
|
||||||
self.pw = kwargs.pop('pw', None)
|
|
||||||
self.presentation_definition = kwargs.pop('presentation_definition', [])
|
self.presentation_definition = kwargs.pop('presentation_definition', [])
|
||||||
self.subject_did = None
|
self.subject_did = None
|
||||||
|
|
||||||
|
@ -53,7 +49,6 @@ class AuthorizeForm(forms.Form):
|
||||||
|
|
||||||
cred = self.user.decrypt_data(
|
cred = self.user.decrypt_data(
|
||||||
c.data,
|
c.data,
|
||||||
self.pw
|
|
||||||
)
|
)
|
||||||
self.subject_did = c.subject_did
|
self.subject_did = c.subject_did
|
||||||
self.list_credentials.append(cred)
|
self.list_credentials.append(cred)
|
||||||
|
@ -85,5 +80,5 @@ class AuthorizeForm(forms.Form):
|
||||||
"verifiable_credential_list": vc_list
|
"verifiable_credential_list": vc_list
|
||||||
}
|
}
|
||||||
unsigned_vp = vp_template.render(context)
|
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)
|
self.vp = create_verifiable_presentation(key_material, unsigned_vp)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import secrets
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from utils.idhub_ssikit import verify_presentation
|
from utils.idhub_ssikit import verify_presentation
|
||||||
|
|
|
@ -16,7 +16,6 @@ from idhub.mixins import UserView
|
||||||
from idhub.models import Event
|
from idhub.models import Event
|
||||||
|
|
||||||
from oidc4vp.forms import AuthorizeForm
|
from oidc4vp.forms import AuthorizeForm
|
||||||
from utils.idhub_ssikit import verify_presentation
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizeView(UserView, FormView):
|
class AuthorizeView(UserView, FormView):
|
||||||
|
@ -39,16 +38,11 @@ class AuthorizeView(UserView, FormView):
|
||||||
kwargs['user'] = self.request.user
|
kwargs['user'] = self.request.user
|
||||||
try:
|
try:
|
||||||
vps = json.loads(self.request.GET.get('presentation_definition'))
|
vps = json.loads(self.request.GET.get('presentation_definition'))
|
||||||
except:
|
except Exception:
|
||||||
vps = []
|
vps = []
|
||||||
kwargs['presentation_definition'] = vps
|
kwargs['presentation_definition'] = vps
|
||||||
kwargs["org"] = self.get_org()
|
kwargs["org"] = self.get_org()
|
||||||
kwargs["code"] = self.request.GET.get('code')
|
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
|
return kwargs
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
|
@ -64,7 +58,7 @@ class AuthorizeView(UserView, FormView):
|
||||||
return redirect(self.success_url)
|
return redirect(self.success_url)
|
||||||
try:
|
try:
|
||||||
authorization = authorization.json()
|
authorization = authorization.json()
|
||||||
except:
|
except Exception:
|
||||||
messages.error(self.request, _("Error sending credential!"))
|
messages.error(self.request, _("Error sending credential!"))
|
||||||
return redirect(self.success_url)
|
return redirect(self.success_url)
|
||||||
|
|
||||||
|
@ -148,7 +142,6 @@ class VerifyView(View):
|
||||||
if len(auth_data) == 2 and auth_data[0].lower() == 'basic':
|
if len(auth_data) == 2 and auth_data[0].lower() == 'basic':
|
||||||
decoded_auth = base64.b64decode(auth_data[1]).decode('utf-8')
|
decoded_auth = base64.b64decode(auth_data[1]).decode('utf-8')
|
||||||
client_id, client_secret = decoded_auth.split(':', 1)
|
client_id, client_secret = decoded_auth.split(':', 1)
|
||||||
org_url = request.GET.get('demand_uri')
|
|
||||||
org = get_object_or_404(
|
org = get_object_or_404(
|
||||||
Organization,
|
Organization,
|
||||||
client_id=client_id,
|
client_id=client_id,
|
||||||
|
|
|
@ -212,13 +212,11 @@ LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"console": {"class": "logging.StreamHandler"},
|
"console": {"level": "DEBUG", "class": "logging.StreamHandler"},
|
||||||
},
|
},
|
||||||
"loggers": {
|
"root": {
|
||||||
"django": {
|
"handlers": ["console"],
|
||||||
"handlers": ["console"],
|
"level": "DEBUG",
|
||||||
"level": "INFO",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue