diff --git a/idhub/admin/forms.py b/idhub/admin/forms.py
index aec6605..b1300fc 100644
--- a/idhub/admin/forms.py
+++ b/idhub/admin/forms.py
@@ -23,6 +23,33 @@ from idhub.models import (
from idhub_auth.models import User
+class TermsConditionsForm(forms.Form):
+ accept = forms.BooleanField(
+ label=_("Accept terms and conditions of the service"),
+ required=False
+ )
+
+ def __init__(self, *args, **kwargs):
+ self.user = kwargs.pop('user', None)
+ super().__init__(*args, **kwargs)
+
+ def clean(self):
+ data = self.cleaned_data
+ if data.get("accept"):
+ self.user.accept_gdpr = True
+ else:
+ self.user.accept_gdpr = False
+ return data
+
+ def save(self, commit=True):
+
+ if commit:
+ self.user.save()
+ return self.user
+
+ return
+
+
class ImportForm(forms.Form):
did = forms.ChoiceField(label=_("Did"), choices=[])
eidas1 = forms.ChoiceField(
diff --git a/idhub/admin/views.py b/idhub/admin/views.py
index eb150e1..cebca94 100644
--- a/idhub/admin/views.py
+++ b/idhub/admin/views.py
@@ -9,7 +9,7 @@ from django_tables2 import SingleTableView
from django.conf import settings
from django.utils.translation import gettext_lazy as _
-from django.views.generic.base import TemplateView
+from django.views.generic.base import TemplateView, View
from django.views.generic.edit import (
CreateView,
DeleteView,
@@ -29,6 +29,7 @@ from idhub.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import (
ImportForm,
MembershipForm,
+ TermsConditionsForm,
SchemaForm,
UserRolForm,
ImportCertificateForm,
@@ -49,6 +50,41 @@ from idhub.models import (
)
+class TermsAndConditionsView(AdminView, FormView):
+ template_name = "idhub/admin/terms_conditions.html"
+ title = _("GDPR")
+ section = ""
+ subtitle = _('Accept Terms and Conditions')
+ icon = 'bi bi-file-earmark-medical'
+ form_class = TermsConditionsForm
+ success_url = reverse_lazy('idhub:admin_dashboard')
+
+ def get_form_kwargs(self):
+ kwargs = super().get_form_kwargs()
+ kwargs['user'] = self.request.user
+ kwargs['initial'] = {"accept": self.request.user.accept_gdpr}
+ return kwargs
+
+ def form_valid(self, form):
+ user = form.save()
+ return super().form_valid(form)
+
+
+class DobleFactorAuthView(AdminView, View):
+ url = reverse_lazy('idhub:admin_dashboard')
+
+ def get(self, request, *args, **kwargs):
+ self.check_valid_user()
+ if not self.request.session.get("2fauth"):
+ return redirect(self.url)
+
+ if self.request.session.get("2fauth") == str(kwargs.get("admin2fauth")):
+ self.request.session.pop("2fauth", None)
+ return redirect(self.url)
+
+ return redirect(reverse_lazy("idhub:login"))
+
+
class DashboardView(AdminView, SingleTableView):
template_name = "idhub/admin/dashboard.html"
table_class = DashboardTable
@@ -119,6 +155,7 @@ class PeopleView(People, TemplateView):
class PeopleActivateView(PeopleView):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
@@ -140,6 +177,7 @@ class PeopleActivateView(PeopleView):
class PeopleDeleteView(PeopleView):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
@@ -304,6 +342,7 @@ class PeopleMembershipDeleteView(PeopleView):
model = Membership
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
@@ -391,6 +430,7 @@ class PeopleRolDeleteView(PeopleView):
model = UserRol
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
user = self.object.user
@@ -454,6 +494,7 @@ class RolDeleteView(AccessControl):
model = Rol
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
@@ -527,6 +568,7 @@ class ServiceDeleteView(AccessControl):
model = Service
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
@@ -571,6 +613,7 @@ class CredentialView(Credentials):
class CredentialJsonView(Credentials):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
pk = kwargs['pk']
self.object = get_object_or_404(
VerificableCredential,
@@ -585,6 +628,7 @@ class RevokeCredentialsView(Credentials):
success_url = reverse_lazy('idhub:admin_credentials')
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
pk = kwargs['pk']
self.object = get_object_or_404(
VerificableCredential,
@@ -604,6 +648,7 @@ class DeleteCredentialsView(Credentials):
success_url = reverse_lazy('idhub:admin_credentials')
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
pk = kwargs['pk']
self.object = get_object_or_404(
VerificableCredential,
@@ -683,6 +728,7 @@ class DidDeleteView(Credentials, DeleteView):
success_url = reverse_lazy('idhub:admin_dids')
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
Event.set_EV_ORG_DID_DELETED_BY_ADMIN(self.object)
@@ -737,6 +783,7 @@ class SchemasView(SchemasMix):
class SchemasDeleteView(SchemasMix):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(Schemas, pk=self.pk)
self.object.delete()
@@ -747,6 +794,7 @@ class SchemasDeleteView(SchemasMix):
class SchemasDownloadView(SchemasMix):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
self.pk = kwargs['pk']
self.object = get_object_or_404(Schemas, pk=self.pk)
@@ -825,6 +873,7 @@ class SchemasImportView(SchemasMix):
class SchemasImportAddView(SchemasMix):
def get(self, request, *args, **kwargs):
+ self.check_valid_user()
file_name = kwargs['file_schema']
schemas_files = os.listdir(settings.SCHEMAS_DIR)
if not file_name in schemas_files:
diff --git a/idhub/email/views.py b/idhub/email/views.py
index 72e0daa..f14e2a5 100644
--- a/idhub/email/views.py
+++ b/idhub/email/views.py
@@ -13,7 +13,11 @@ logger = logging.getLogger(__name__)
class NotifyActivateUserByEmail:
- def get_email_context(self, user):
+ subject_template_name = 'idhub/admin/registration/activate_user_subject.txt'
+ email_template_name = 'idhub/admin/registration/activate_user_email.txt'
+ html_email_template_name = 'idhub/admin/registration/activate_user_email.html'
+
+ def get_email_context(self, user, token):
"""
Define a new context with a token for put in a email
when send a email for add a new password
@@ -22,35 +26,35 @@ class NotifyActivateUserByEmail:
current_site = get_current_site(self.request)
site_name = current_site.name
domain = current_site.domain
+ if not token:
+ token = default_token_generator.make_token(user)
+
context = {
'email': user.email,
'domain': domain,
'site_name': site_name,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'user': user,
- 'token': default_token_generator.make_token(user),
+ 'token': token,
'protocol': protocol,
}
return context
- def send_email(self, user):
+ def send_email(self, user, token=None):
"""
Send a email when a user is activated.
"""
- context = self.get_email_context(user)
- subject_template_name = 'idhub/admin/registration/activate_user_subject.txt'
- email_template_name = 'idhub/admin/registration/activate_user_email.txt'
- html_email_template_name = 'idhub/admin/registration/activate_user_email.html'
- subject = loader.render_to_string(subject_template_name, context)
+ context = self.get_email_context(user, token)
+ 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(email_template_name, context)
+ 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(html_email_template_name, context)
+ html_email = loader.render_to_string(self.html_email_template_name, context)
email_message.attach_alternative(html_email, 'text/html')
try:
if settings.DEVELOPMENT:
diff --git a/idhub/migrations/0001_initial.py b/idhub/migrations/0001_initial.py
deleted file mode 100644
index bc9f011..0000000
--- a/idhub/migrations/0001_initial.py
+++ /dev/null
@@ -1,367 +0,0 @@
-# Generated by Django 4.2.5 on 2024-01-18 11:32
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
- initial = True
-
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ]
-
- operations = [
- migrations.CreateModel(
- name='DID',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- (
- 'type',
- models.PositiveSmallIntegerField(
- choices=[(1, 'Key'), (2, 'Web')], verbose_name='Type'
- ),
- ),
- ('created_at', models.DateTimeField(auto_now=True)),
- ('label', models.CharField(max_length=50, verbose_name='Label')),
- ('did', models.CharField(max_length=250)),
- ('key_material', models.TextField()),
- ('eidas1', models.BooleanField(default=False)),
- ('didweb_document', models.TextField()),
- (
- 'user',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='dids',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='File_datas',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('file_name', models.CharField(max_length=250)),
- ('success', models.BooleanField(default=True)),
- ('created_at', models.DateTimeField(auto_now=True)),
- ],
- ),
- migrations.CreateModel(
- name='Rol',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('name', models.CharField(max_length=250, verbose_name='name')),
- (
- 'description',
- models.CharField(
- max_length=250, null=True, verbose_name='Description'
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='Schemas',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('type', models.CharField(max_length=250)),
- ('file_schema', models.CharField(max_length=250)),
- ('data', models.TextField()),
- ('created_at', models.DateTimeField(auto_now=True)),
- ],
- ),
- migrations.CreateModel(
- name='Service',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('domain', models.CharField(max_length=250, verbose_name='Domain')),
- (
- 'description',
- models.CharField(max_length=250, verbose_name='Description'),
- ),
- ('rol', models.ManyToManyField(to='idhub.rol')),
- ],
- ),
- migrations.CreateModel(
- name='VCTemplate',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('wkit_template_id', models.CharField(max_length=250)),
- ('data', models.TextField()),
- ],
- ),
- migrations.CreateModel(
- name='VerificableCredential',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('id_string', models.CharField(max_length=250)),
- ('verified', models.BooleanField()),
- ('created_on', models.DateTimeField(auto_now=True)),
- ('issued_on', models.DateTimeField(null=True)),
- ('data', models.TextField()),
- ('csv_data', models.TextField()),
- ('hash', models.CharField(max_length=260)),
- (
- 'status',
- models.PositiveSmallIntegerField(
- choices=[
- (1, 'Enabled'),
- (2, 'Issued'),
- (3, 'Revoked'),
- (4, 'Expired'),
- ],
- default=1,
- ),
- ),
- (
- 'eidas1_did',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- to='idhub.did',
- ),
- ),
- (
- 'issuer_did',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='vcredentials',
- to='idhub.did',
- ),
- ),
- (
- 'schema',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='vcredentials',
- to='idhub.schemas',
- ),
- ),
- (
- 'subject_did',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='subject_credentials',
- to='idhub.did',
- ),
- ),
- (
- 'user',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='vcredentials',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='Membership',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- (
- 'type',
- models.PositiveSmallIntegerField(
- choices=[(1, 'Beneficiary'), (2, 'Employee'), (3, 'Member')],
- verbose_name='Type of membership',
- ),
- ),
- (
- 'start_date',
- models.DateField(
- blank=True,
- help_text='What date did the membership start?',
- null=True,
- verbose_name='Start date',
- ),
- ),
- (
- 'end_date',
- models.DateField(
- blank=True,
- help_text='What date will the membership end?',
- null=True,
- verbose_name='End date',
- ),
- ),
- (
- 'user',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='memberships',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='Event',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('created', models.DateTimeField(auto_now=True, verbose_name='Date')),
- (
- 'message',
- models.CharField(max_length=350, verbose_name='Description'),
- ),
- (
- 'type',
- models.PositiveSmallIntegerField(
- choices=[
- (1, 'User registered'),
- (2, 'User welcomed'),
- (3, 'Data update requested by user'),
- (
- 4,
- 'Data update requested. Pending approval by administrator',
- ),
- (5, "User's data updated by admin"),
- (6, 'Your data updated by admin'),
- (7, 'User deactivated by admin'),
- (8, 'DID created by user'),
- (9, 'DID created'),
- (10, 'DID deleted'),
- (11, 'Credential deleted by user'),
- (12, 'Credential deleted'),
- (13, 'Credential issued for user'),
- (14, 'Credential issued'),
- (15, 'Credential presented by user'),
- (16, 'Credential presented'),
- (17, 'Credential enabled'),
- (18, 'Credential available'),
- (19, 'Credential revoked by admin'),
- (20, 'Credential revoked'),
- (21, 'Role created by admin'),
- (22, 'Role modified by admin'),
- (23, 'Role deleted by admin'),
- (24, 'Service created by admin'),
- (25, 'Service modified by admin'),
- (26, 'Service deleted by admin'),
- (27, 'Organisational DID created by admin'),
- (28, 'Organisational DID deleted by admin'),
- (29, 'User deactivated'),
- (30, 'User activated'),
- ],
- verbose_name='Event',
- ),
- ),
- (
- 'user',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='events',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='UserRol',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- (
- 'service',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='users',
- to='idhub.service',
- verbose_name='Service',
- ),
- ),
- (
- 'user',
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name='roles',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- options={
- 'unique_together': {('user', 'service')},
- },
- ),
- ]
diff --git a/idhub/mixins.py b/idhub/mixins.py
index a87d821..f101f0e 100644
--- a/idhub/mixins.py
+++ b/idhub/mixins.py
@@ -1,14 +1,48 @@
from django.contrib.auth.mixins import LoginRequiredMixin
-from django.contrib.auth import views as auth_views
-from django.urls import reverse_lazy, resolve
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
from django.core.cache import cache
+class Http403(PermissionDenied):
+ status_code = 403
+ default_detail = _('Permission denied. User is not authenticated')
+ default_code = 'forbidden'
+
+ def __init__(self, detail=None, code=None):
+ if detail is not None:
+ self.detail = details or self.default_details
+ if code is not None:
+ self.code = code or self.default_code
+
+
class UserView(LoginRequiredMixin):
login_url = "/login/"
wallet = False
+ path_terms = [
+ 'admin_terms_and_conditions',
+ 'user_terms_and_conditions',
+ 'user_gdpr',
+ ]
+
+ def get(self, request, *args, **kwargs):
+ response = super().get(request, *args, **kwargs)
+ url = self.check_gdpr()
+ if url:
+ return url
+
+ return response
+
+ def post(self, request, *args, **kwargs):
+ response = super().post(request, *args, **kwargs)
+ url = self.check_gdpr()
+ if url:
+ return url
+
+ return response
def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS")
@@ -32,12 +66,29 @@ class UserView(LoginRequiredMixin):
})
return context
+ def check_gdpr(self):
+ if not self.request.user.accept_gdpr:
+ url = reverse_lazy("idhub:user_terms_and_conditions")
+ if self.request.user.is_admin:
+ url = reverse_lazy("idhub:admin_terms_and_conditions")
+ if resolve(self.request.path).url_name not in self.path_terms:
+ return redirect(url)
+
class AdminView(UserView):
def get(self, request, *args, **kwargs):
- if not request.user.is_admin:
- url = reverse_lazy('idhub:user_dashboard')
- return redirect(url)
-
+ self.check_valid_user()
return super().get(request, *args, **kwargs)
+
+ def post(self, request, *args, **kwargs):
+ self.check_valid_user()
+ return super().post(request, *args, **kwargs)
+
+ def check_valid_user(self):
+ if not self.request.user.is_admin:
+ raise Http403()
+
+ if self.request.session.get("2fauth"):
+ raise Http403()
+
diff --git a/idhub/templates/auth/2fadmin.html b/idhub/templates/auth/2fadmin.html
new file mode 100644
index 0000000..4dc2ae6
--- /dev/null
+++ b/idhub/templates/auth/2fadmin.html
@@ -0,0 +1,19 @@
+{% extends "auth/login_base.html" %}
+{% load i18n django_bootstrap5 %}
+
+{% block login_content %}
+
+
+
+
{% trans 'Doble Factor of Authentication' %}
+
+
+
+
+
+
+ {% trans "We have sent an email with a link that you have to select in order to login." %}
+
+
+
+{% endblock %}
diff --git a/idhub/templates/auth/2fadmin_email.html b/idhub/templates/auth/2fadmin_email.html
new file mode 100644
index 0000000..d2253c5
--- /dev/null
+++ b/idhub/templates/auth/2fadmin_email.html
@@ -0,0 +1,26 @@
+{% load i18n %}{% autoescape off %}
+
+{% blocktrans %}You're receiving this email because you try to access in {{ site_name }}.{% endblocktrans %}
+
+
+
+{% trans "Please go to the following page" %}
+
+
+
+{% block reset_link %}
+
+{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %}
+
+{% endblock %}
+
+
+
+{% trans "Thanks for using our site!" %}
+
+
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+
+{% endautoescape %}
diff --git a/idhub/templates/auth/2fadmin_email.txt b/idhub/templates/auth/2fadmin_email.txt
new file mode 100644
index 0000000..a9ef3e5
--- /dev/null
+++ b/idhub/templates/auth/2fadmin_email.txt
@@ -0,0 +1,14 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}You're receiving this email because you try to access in {{ site_name }}.{% endblocktrans %}
+
+{% trans "Please go to the following page" %}
+{% block reset_link %}
+{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %}
+{% endblock %}
+{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/idhub/templates/auth/2fadmin_email_subject.txt b/idhub/templates/auth/2fadmin_email_subject.txt
new file mode 100644
index 0000000..6d3bb21
--- /dev/null
+++ b/idhub/templates/auth/2fadmin_email_subject.txt
@@ -0,0 +1,3 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}Authentication in {{ site_name }}{% endblocktrans %}
+{% endautoescape %}
\ No newline at end of file
diff --git a/idhub/templates/idhub/admin/terms_conditions.html b/idhub/templates/idhub/admin/terms_conditions.html
new file mode 100644
index 0000000..51f8b6c
--- /dev/null
+++ b/idhub/templates/idhub/admin/terms_conditions.html
@@ -0,0 +1,57 @@
+{% extends "idhub/base_admin.html" %}
+{% load i18n %}
+
+{% block content %}
+
+
+ {{ subtitle }}
+
+{% load django_bootstrap5 %}
+
+
+
+
+
+
+
+
Here we write the info about GDPR
+
+
+
+
+
+{% endblock %}
diff --git a/idhub/templates/idhub/base.html b/idhub/templates/idhub/base.html
index 52f8f33..e579a81 100644
--- a/idhub/templates/idhub/base.html
+++ b/idhub/templates/idhub/base.html
@@ -140,9 +140,6 @@
diff --git a/idhub/templates/idhub/base_admin.html b/idhub/templates/idhub/base_admin.html
index c97f165..271d6d5 100644
--- a/idhub/templates/idhub/base_admin.html
+++ b/idhub/templates/idhub/base_admin.html
@@ -170,9 +170,6 @@
diff --git a/idhub/templates/idhub/user/gdpr.html b/idhub/templates/idhub/user/gdpr.html
index 1ac25fd..16476b8 100644
--- a/idhub/templates/idhub/user/gdpr.html
+++ b/idhub/templates/idhub/user/gdpr.html
@@ -6,4 +6,7 @@
{{ subtitle }}
+Gdpr info
+If you want accept or revoke the Gdpr go to:
+ Terms and conditions
{% endblock %}
diff --git a/idhub/templates/idhub/user/terms_conditions.html b/idhub/templates/idhub/user/terms_conditions.html
new file mode 100644
index 0000000..8a02175
--- /dev/null
+++ b/idhub/templates/idhub/user/terms_conditions.html
@@ -0,0 +1,57 @@
+{% extends "idhub/base.html" %}
+{% load i18n %}
+
+{% block content %}
+
+
+ {{ subtitle }}
+
+{% load django_bootstrap5 %}
+
+
+
+
+
+
+
+
Here we write the info about GDPR
+
+
+
+
+
+{% endblock %}
diff --git a/idhub/templates/templates/musician/address_check_delete.html b/idhub/templates/templates/musician/address_check_delete.html
deleted file mode 100644
index 27981d4..0000000
--- a/idhub/templates/templates/musician/address_check_delete.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/address_form.html b/idhub/templates/templates/musician/address_form.html
deleted file mode 100644
index de21067..0000000
--- a/idhub/templates/templates/musician/address_form.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends "musician/base.html" %}
-{% load bootstrap4 i18n %}
-
-{% block content %}
-{{ service.verbose_name }}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/addresses.html b/idhub/templates/templates/musician/addresses.html
deleted file mode 100644
index 1ebc8b7..0000000
--- a/idhub/templates/templates/musician/addresses.html
+++ /dev/null
@@ -1,41 +0,0 @@
-{% extends "musician/mail_base.html" %}
-{% load i18n %}
-
-{% block tabcontent %}
-
-
-
-
-
-
-
-
-
-
- {% trans "Email" %} |
- {% trans "Domain" %} |
- {% trans "Mailboxes" %} |
- {% trans "Forward" %} |
-
-
-
- {% for obj in object_list %}
-
- {{ obj.full_address_name }} |
- {{ obj.domain.name }} |
-
- {% for mailbox in obj.mailboxes %}
- {{ mailbox.name }}
- {% if not forloop.last %} {% endif %}
- {% endfor %}
- |
- {{ obj.forward }} |
-
- {% endfor %}
-
- {% include "musician/components/table_paginator.html" %}
-
-
{% trans "New mail address" %}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/billing.html b/idhub/templates/templates/musician/billing.html
deleted file mode 100644
index 75f2580..0000000
--- a/idhub/templates/templates/musician/billing.html
+++ /dev/null
@@ -1,41 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n l10n %}
-
-{% block content %}
-
-{% trans "Billing" %}
-{% trans "Billing page description." %}
-
-
-
-
-
-
-
-
-
-
-
- {% trans "Number" %} |
- {% trans "Bill date" %} |
- {% trans "Type" %} |
- {% trans "Total" %} |
- {% trans "Download PDF" %} |
-
-
-
- {% for bill in object_list %}
-
- {{ bill.number }} |
- {{ bill.created_on|date:"SHORT_DATE_FORMAT" }} |
- {{ bill.type }} |
- {{ bill.total|floatformat:2|localize }}€ |
- |
-
- {% endfor %}
-
-{# TODO: define proper colspan #}
-{% include "musician/components/table_paginator.html" %}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/components/paginator.html b/idhub/templates/templates/musician/components/paginator.html
deleted file mode 100644
index 9a7a406..0000000
--- a/idhub/templates/templates/musician/components/paginator.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{# #}
-
-
{{ page_obj.paginator.count }} items in total
-
- {% if page_obj.has_previous %}
-
«
-
‹
- {% endif %}
- Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
- {% if page_obj.has_next %}
-
›
-
»
- {% endif %}
-
-
-
-
-
diff --git a/idhub/templates/templates/musician/components/table_paginator.html b/idhub/templates/templates/musician/components/table_paginator.html
deleted file mode 100644
index 913d5ae..0000000
--- a/idhub/templates/templates/musician/components/table_paginator.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{# #}
-{% load i18n %}
-
-
-
- {{ page_obj.paginator.count }} items in total |
-
-
- |
-
-
- |
-
-
diff --git a/idhub/templates/templates/musician/components/usage_progress_bar.html b/idhub/templates/templates/musician/components/usage_progress_bar.html
deleted file mode 100644
index b35e84c..0000000
--- a/idhub/templates/templates/musician/components/usage_progress_bar.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% comment %}
-Resource usage rendered as bootstrap progress bar
-
-Expected parameter: detail
-Expected structure: dictionary or object with attributes:
- - usage (int): 125
- - total (int): 200
- - unit (string): 'MB'
- - percent (int: [0, 25, 50, 75, 100]: 75
-{% endcomment %}
-
-
- {% if detail %}
- {{ detail.usage }} {{ detail.unit }}
- {% else %}
- N/A
- {% endif %}
-
-
diff --git a/idhub/templates/templates/musician/dashboard.html b/idhub/templates/templates/musician/dashboard.html
deleted file mode 100644
index d359fcb..0000000
--- a/idhub/templates/templates/musician/dashboard.html
+++ /dev/null
@@ -1,161 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-{% trans "Welcome back" %} {{ profile.username }}
-{% if profile.last_login %}
-{% blocktrans with last_login=profile.last_login|date:"SHORT_DATE_FORMAT" %}Last time you logged in was: {{ last_login }}{% endblocktrans %}
-{% else %}
-{% trans "It's the first time you log into the system, welcome on board!" %}
-{% endif %}
-
-
- {% for resource, usage in resource_usage.items %}
-
-
-
{{ usage.verbose_name }}
- {% include "musician/components/usage_progress_bar.html" with detail=usage.data %}
- {% if usage.data.alert %}
-
- {{ usage.data.alert }}
-
- {% endif %}
-
-
- {% endfor %}
-
-
-
{% trans "Notifications" %}
- {% for message in notifications %}
-
{{ message }}
- {% empty %}
-
{% trans "There is no notifications at this time." %}
- {% endfor %}
-
-
-
-
-
-{% trans "Your domains and websites" %}
-{% trans "Dashboard page description." %}
-
-{% for domain in domains %}
-
-
-
-
-
{% trans "Mail" %}
-
-
- {{ domain.addresses|length }} {% trans "mail addresses created" %}
-
-
-
-
-
{% trans "Mail list" %}
-
-
-
-
-
{% trans "Software as a Service" %}
-
-
{% trans "Nothing installed" %}
-
-
-
-
-
{% trans "Disk usage" %}
-
-
- {% include "musician/components/usage_progress_bar.html" with detail=domain.usage %}
-
-
-
-
-
-
-{% endfor %}
-
-
-
-
-
-
-
-
-
{% trans "FTP access:" %}
- {# Translators: domain configuration detail modal #}
-
{% trans "Contact with the support team to get details concerning FTP access." %}
- {% comment %}
-
-
username
-
password
- {% endcomment %}
-
-
-
{% trans "No website configured." %}
-
- root directory
- type
-
-
-
-
-
-
-
-{% endblock %}
-{% block extrascript %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/databases.html b/idhub/templates/templates/musician/databases.html
deleted file mode 100644
index cf71d1f..0000000
--- a/idhub/templates/templates/musician/databases.html
+++ /dev/null
@@ -1,68 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-{{ service.verbose_name }}
-{{ service.description }}
-
-{% for database in object_list %}
-
-
-
-
-
Database users
-
- {% for user in database.users %}
- {# TODO(@slamora) render in two columns #}
- - {{ user.username }}
- {% empty %}
- - {% trans "No users for this database." %}
- {% endfor %}
-
-
-
-
Database usage
-
- {% include "musician/components/usage_progress_bar.html" with detail=database.usage %}
-
-
-
-
-
-{% empty %}
-
-
-
-
-
- {# Translators: database page when there isn't any database. #}
-
{% trans "Ooops! Looks like there is nothing here!" %}
-
-
-
-
-{% endfor %}
-
- {% if object_list|length > 0 %}
- {% include "musician/components/paginator.html" %}
- {% endif %}
-{% endblock %}
diff --git a/idhub/templates/templates/musician/domain_detail.html b/idhub/templates/templates/musician/domain_detail.html
deleted file mode 100644
index 761c331..0000000
--- a/idhub/templates/templates/musician/domain_detail.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-{% trans "Go back" %}
-
-{% trans "DNS settings for" %} {{ object.name }}
-{% trans "DNS settings page description." %}
-
-
-
-
-
-
-
-
- {% trans "Type" %} |
- {% trans "Value" %} |
-
-
-
- {% for record in object.records %}
-
- {{ record.type }} |
- {{ record.value }} |
-
- {% endfor %}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mail_base.html b/idhub/templates/templates/musician/mail_base.html
deleted file mode 100644
index 9445f7f..0000000
--- a/idhub/templates/templates/musician/mail_base.html
+++ /dev/null
@@ -1,32 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-{% if active_domain %}
-{% trans "Go to global" %}
-{% endif %}
-
-{{ service.verbose_name }}
- {% if active_domain %}{% trans "for" %} {{ active_domain.name }}{% endif %}
-
-{{ service.description }}
-
-{% with request.resolver_match.url_name as url_name %}
-
-
-{% endwith %}
-
-
- {% block tabcontent %}
- {% endblock %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mailbox_change_password.html b/idhub/templates/templates/musician/mailbox_change_password.html
deleted file mode 100644
index e18b95a..0000000
--- a/idhub/templates/templates/musician/mailbox_change_password.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "musician/base.html" %}
-{% load bootstrap4 i18n %}
-
-{% block content %}
-
{% trans "Change password" %}: {{ object.name }}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mailbox_check_delete.html b/idhub/templates/templates/musician/mailbox_check_delete.html
deleted file mode 100644
index 18b9249..0000000
--- a/idhub/templates/templates/musician/mailbox_check_delete.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mailbox_form.html b/idhub/templates/templates/musician/mailbox_form.html
deleted file mode 100644
index 5fb9465..0000000
--- a/idhub/templates/templates/musician/mailbox_form.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{% extends "musician/base.html" %}
-{% load bootstrap4 i18n %}
-
-{% block content %}
-
{{ service.verbose_name }}
-
-{% if extra_mailbox %}
-
- {% trans "Warning!" %} {% trans "You have reached the limit of mailboxes of your subscription so extra fees may apply." %}
-
-
-{% endif %}
-
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mailboxes.html b/idhub/templates/templates/musician/mailboxes.html
deleted file mode 100644
index a9f3700..0000000
--- a/idhub/templates/templates/musician/mailboxes.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends "musician/mail_base.html" %}
-{% load i18n %}
-
-{% block tabcontent %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/mailinglists.html b/idhub/templates/templates/musician/mailinglists.html
deleted file mode 100644
index 6ff509e..0000000
--- a/idhub/templates/templates/musician/mailinglists.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-{% if active_domain %}
-
{% trans "Go to global" %}
-{% endif %}
-
-
{{ service.verbose_name }}{% if active_domain %} {% trans "for" %} {{ active_domain.name }}{% endif %}
-
{{ service.description }}
-
-
-
-
-
-
-
-
-
-
-
- Name |
- Status |
- Address |
- Admin email |
- Configure |
-
-
-
- {% for resource in object_list %}
-
- {{ resource.name }} |
- {% if resource.is_active %}
- {% trans "Active" %} |
- {% else %}
- {% trans "Inactive" %} |
- {% endif %}
- {{ resource.address_name}} |
- {{ resource.admin_email }} |
- Mailtrain |
-
- {% endfor %}
-
- {% include "musician/components/table_paginator.html" %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/profile.html b/idhub/templates/templates/musician/profile.html
deleted file mode 100644
index f6bdbce..0000000
--- a/idhub/templates/templates/musician/profile.html
+++ /dev/null
@@ -1,65 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-
{% trans "Profile" %}
-
{% trans "Little description on profile page." %}
-
-
-
-
-
-
-
-
-
-
-
-
{{ profile.username }}
-
{{ profile.type }}
-
{% trans "Preferred language:" %} {{ profile.language|language_name_local }}
-
- {% comment %}
-
-
- {% endcomment %}
-
-
-
- {% with profile.billing as contact %}
-
-
-
-
{{ contact.name }}
-
{{ contact.address }}
-
- {{ contact.zipcode }}
- {{ contact.city }}
- {{ contact.country }}
-
-
- {{ contact.vat }}
-
-
-
- {% trans "payment method:" %} {{ payment.method }}
-
-
- {% if payment.method == 'SEPADirectDebit' %}
- IBAN {{ payment.data.iban }}
- {% else %}
- {# #}
- Details: {{ payment.data }}
- {% endif %}
-
-
-
-
-
-{% endwith %}
-{% endblock %}
diff --git a/idhub/templates/templates/musician/saas.html b/idhub/templates/templates/musician/saas.html
deleted file mode 100644
index 4da034f..0000000
--- a/idhub/templates/templates/musician/saas.html
+++ /dev/null
@@ -1,56 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n %}
-
-{% block content %}
-
-
{{ service.verbose_name }}
-
{{ service.description }}
-
-{% for saas in object_list %}
-
-
-
-
-
{{ saas.service|capfirst }}
-
-
-
-
{% trans "Service info" %}
- {{ saas.is_active|yesno }}
- {% for key, value in saas.data.items %}
- {{ value }}
- {% endfor %}
-
-
-
-
- {% empty %}
-
-
-
-
-
- {# Translators: saas page when there isn't any saas. #}
-
{% trans "Ooops! Looks like there is nothing here!" %}
-
-
-
-
-{% endfor %}
-
-{% endblock %}
diff --git a/idhub/templates/templates/musician/service_list.html b/idhub/templates/templates/musician/service_list.html
deleted file mode 100644
index d413fc8..0000000
--- a/idhub/templates/templates/musician/service_list.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{% extends "musician/base.html" %}
-{% load i18n musician %}
-
-{% block content %}
-
-
{{ service.verbose_name }}
-
{{ service.description }}
-
-
-
-
- {% for field_name in service.fields %}
- {{ field_name }} |
- {% endfor %}
-
-
-
- {% for resource in object_list %}
-
- {% for field_name in service.fields %}
- {{ resource|get_item:field_name }} |
- {% endfor %}
-
- {% endfor %}
-
- {% include "musician/components/table_paginator.html" %}
-
-{% endblock %}
diff --git a/idhub/urls.py b/idhub/urls.py
index 648f155..d107b3f 100644
--- a/idhub/urls.py
+++ b/idhub/urls.py
@@ -17,7 +17,12 @@ Including another URLconf
from django.contrib.auth import views as auth_views
from django.views.generic import RedirectView
from django.urls import path, reverse_lazy
-from .views import LoginView, PasswordResetConfirmView, serve_did
+from .views import (
+ LoginView,
+ PasswordResetConfirmView,
+ serve_did,
+ DobleFactorSendView,
+)
from .admin import views as views_admin
from .user import views as views_user
# from .verification_portal import views as views_verification_portal
@@ -95,6 +100,8 @@ urlpatterns = [
path('user/credentials_presentation/demand',
views_user.DemandAuthorizationView.as_view(),
name='user_demand_authorization'),
+ path('user/terms/', views_user.TermsAndConditionsView.as_view(),
+ name='user_terms_and_conditions'),
# Admin
path('admin/dashboard/', views_admin.DashboardView.as_view(),
@@ -177,8 +184,13 @@ urlpatterns = [
name='admin_schemas_import_add'),
path('admin/import', views_admin.ImportView.as_view(),
name='admin_import'),
+ path('admin/terms/', views_admin.TermsAndConditionsView.as_view(),
+ name='admin_terms_and_conditions'),
path('admin/import/new', views_admin.ImportAddView.as_view(),
name='admin_import_add'),
+ path('admin/auth/
', views_admin.DobleFactorAuthView.as_view(),
+ name='admin_2fauth'),
+ path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),
path('did-registry//did.json', serve_did)
diff --git a/idhub/user/forms.py b/idhub/user/forms.py
index 58c8ff5..0277034 100644
--- a/idhub/user/forms.py
+++ b/idhub/user/forms.py
@@ -16,6 +16,33 @@ class ProfileForm(forms.ModelForm):
fields = ('first_name', 'last_name', 'email')
+class TermsConditionsForm(forms.Form):
+ accept = forms.BooleanField(
+ label=_("Accept terms and conditions of the service"),
+ required=False
+ )
+
+ def __init__(self, *args, **kwargs):
+ self.user = kwargs.pop('user', None)
+ super().__init__(*args, **kwargs)
+
+ def clean(self):
+ data = self.cleaned_data
+ if data.get("accept"):
+ self.user.accept_gdpr = True
+ else:
+ self.user.accept_gdpr = False
+ return data
+
+ def save(self, commit=True):
+
+ if commit:
+ self.user.save()
+ return self.user
+
+ return
+
+
class RequestCredentialForm(forms.Form):
did = forms.ChoiceField(label=_("Did"), choices=[])
credential = forms.ChoiceField(label=_("Credential"), choices=[])
diff --git a/idhub/user/views.py b/idhub/user/views.py
index aa0b2a7..3f69faf 100644
--- a/idhub/user/views.py
+++ b/idhub/user/views.py
@@ -31,7 +31,8 @@ from django.conf import settings
from idhub.user.forms import (
ProfileForm,
RequestCredentialForm,
- DemandAuthorizationForm
+ DemandAuthorizationForm,
+ TermsConditionsForm
)
from utils import certs
from idhub.mixins import UserView
@@ -105,6 +106,26 @@ class CredentialsView(MyWallet, TemplateView):
})
return context
+
+class TermsAndConditionsView(UserView, FormView):
+ template_name = "idhub/user/terms_conditions.html"
+ title = _("GDPR")
+ section = ""
+ subtitle = _('Accept Terms and Conditions')
+ icon = 'bi bi-file-earmark-medical'
+ form_class = TermsConditionsForm
+ success_url = reverse_lazy('idhub:user_dashboard')
+
+ def get_form_kwargs(self):
+ kwargs = super().get_form_kwargs()
+ kwargs['user'] = self.request.user
+ kwargs['initial'] = {"accept": self.request.user.accept_gdpr}
+ return kwargs
+
+ def form_valid(self, form):
+ user = form.save()
+ return super().form_valid(form)
+
class CredentialView(MyWallet, TemplateView):
template_name = "idhub/user/credential.html"
diff --git a/idhub/verification_portal/__init__.py b/idhub/verification_portal/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/idhub/verification_portal/models.py b/idhub/verification_portal/models.py
deleted file mode 100644
index 0bd203a..0000000
--- a/idhub/verification_portal/models.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from django.db import models
-
-
-class VPVerifyRequest(models.Model):
- """
- `nonce` is an opaque random string used to lookup verification requests. URL-safe.
- Example: "UPBQ3JE2DGJYHP5CPSCRIGTHRTCYXMQPNQ"
- `expected_credentials` is a JSON list of credential types that must be present in this VP.
- Example: ["FinancialSituationCredential", "HomeConnectivitySurveyCredential"]
- `expected_contents` is a JSON object that places optional constraints on the contents of the
- returned VP.
- Example: [{"FinancialSituationCredential": {"financial_vulnerability_score": "7"}}]
- `action` is (for now) a JSON object describing the next steps to take if this verification
- is successful. For example "send mail to with and "
- Example: {"action": "send_mail", "params": {"to": "orders@somconnexio.coop", "subject": "New client", "body": ...}
- `response` is a URL that the user's wallet will redirect the user to.
- `submitted_on` is used (by a cronjob) to purge old entries that didn't complete verification
- """
- nonce = models.CharField(max_length=50)
- expected_credentials = models.CharField(max_length=255)
- expected_contents = models.TextField()
- action = models.TextField()
- response_or_redirect = models.CharField(max_length=255)
- submitted_on = models.DateTimeField(auto_now=True)
diff --git a/idhub/verification_portal/views.py b/idhub/verification_portal/views.py
deleted file mode 100644
index 486f4f7..0000000
--- a/idhub/verification_portal/views.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import json
-
-from django.core.mail import send_mail
-from django.http import HttpResponse, HttpResponseRedirect
-
-from utils.idhub_ssikit import verify_presentation
-from .models import VPVerifyRequest
-from django.shortcuts import get_object_or_404
-from more_itertools import flatten, unique_everseen
-
-
-def verify(request):
- assert request.method == "POST"
- # TODO: incorporate request.POST["presentation_submission"] as schema definition
- (presentation_valid, _) = verify_presentation(request.POST["vp_token"])
- if not presentation_valid:
- raise Exception("Failed to verify signature on the given Verifiable Presentation.")
- vp = json.loads(request.POST["vp_token"])
- nonce = vp["nonce"]
- # "vr" = verification_request
- vr = get_object_or_404(VPVerifyRequest, nonce=nonce) # TODO: return meaningful error, not 404
- # Get a list of all included verifiable credential types
- included_credential_types = unique_everseen(flatten([
- vc["type"] for vc in vp["verifiableCredential"]
- ]))
- # Check that it matches what we requested
- for requested_vc_type in json.loads(vr.expected_credentials):
- if requested_vc_type not in included_credential_types:
- raise Exception("You're missing some credentials we requested!") # TODO: return meaningful error
- # Perform whatever action we have to do
- action = json.loads(vr.action)
- if action["action"] == "send_mail":
- subject = action["params"]["subject"]
- to_email = action["params"]["to"]
- from_email = "noreply@verifier-portal"
- body = request.POST["vp-token"]
- send_mail(
- subject,
- body,
- from_email,
- [to_email]
- )
- elif action["action"] == "something-else":
- pass
- else:
- raise Exception("Unknown action!")
- # OK! Your verifiable presentation was successfully presented.
- return HttpResponseRedirect(vr.response_or_redirect)
-
diff --git a/idhub/views.py b/idhub/views.py
index f513353..7a525b1 100644
--- a/idhub/views.py
+++ b/idhub/views.py
@@ -1,13 +1,18 @@
-from django.shortcuts import get_object_or_404
-from django.urls import reverse_lazy
+import uuid
+
from django.conf import settings
from django.core.cache import cache
-from django.utils.translation import gettext_lazy as _
+from django.urls import reverse_lazy
+from django.views.generic.base import TemplateView
from django.contrib.auth import views as auth_views
from django.contrib.auth import login as auth_login
-from django.http import HttpResponseRedirect, HttpResponse
+from django.utils.translation import gettext_lazy as _
+from django.shortcuts import get_object_or_404, redirect
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import HttpResponseRedirect, HttpResponse, Http404
from idhub.models import DID
+from idhub.email.views import NotifyActivateUserByEmail
from trustchain_idhub import settings
@@ -41,6 +46,9 @@ class LoginView(auth_views.LoginView):
# )
# cache.set("KEY_DIDS", encryption_key, None)
cache.set("KEY_DIDS", sensitive_data_encryption_key, None)
+ if not settings.DEVELOPMENT:
+ 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,
@@ -69,3 +77,23 @@ def serve_did(request, did_id):
retval = HttpResponse(document)
retval.headers["Content-Type"] = "application/json"
return retval
+
+
+class DobleFactorSendView(LoginRequiredMixin, NotifyActivateUserByEmail, TemplateView):
+ template_name = 'auth/2fadmin.html'
+ subject_template_name = 'auth/2fadmin_email_subject.txt'
+ email_template_name = 'auth/2fadmin_email.txt'
+ html_email_template_name = 'auth/2fadmin_email.html'
+
+ def get(self, request, *args, **kwargs):
+ if not request.user.is_admin:
+ raise Http404
+
+ f2auth = self.request.session.get("2fauth")
+ if not f2auth:
+ raise Http404
+
+ self.send_email(self.request.user, token=f2auth)
+ return super().get(request, *args, **kwargs)
+
+
diff --git a/idhub_auth/migrations/0001_initial.py b/idhub_auth/migrations/0001_initial.py
deleted file mode 100644
index 840bc0b..0000000
--- a/idhub_auth/migrations/0001_initial.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Generated by Django 4.2.5 on 2024-01-18 11:32
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
- initial = True
-
- dependencies = []
-
- operations = [
- migrations.CreateModel(
- name='User',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('password', models.CharField(max_length=128, verbose_name='password')),
- (
- 'last_login',
- models.DateTimeField(
- blank=True, null=True, verbose_name='last login'
- ),
- ),
- (
- 'email',
- models.EmailField(
- max_length=255, unique=True, verbose_name='Email address'
- ),
- ),
- ('is_active', models.BooleanField(default=True)),
- ('is_admin', models.BooleanField(default=False)),
- (
- 'first_name',
- models.CharField(
- blank=True, max_length=255, null=True, verbose_name='First name'
- ),
- ),
- (
- 'last_name',
- models.CharField(
- blank=True, max_length=255, null=True, verbose_name='Last name'
- ),
- ),
- ('encrypted_sensitive_data', models.CharField(max_length=255)),
- ('salt', models.CharField(max_length=255)),
- ],
- options={
- 'abstract': False,
- },
- ),
- ]
diff --git a/idhub_auth/models.py b/idhub_auth/models.py
index aa3e5b7..e89bc35 100644
--- a/idhub_auth/models.py
+++ b/idhub_auth/models.py
@@ -51,6 +51,7 @@ class User(AbstractBaseUser):
last_name = models.CharField(_("Last name"), max_length=255, blank=True, null=True)
encrypted_sensitive_data = models.CharField(max_length=255)
salt = models.CharField(max_length=255)
+ accept_gdpr = models.BooleanField(default=False)
objects = UserManager()
diff --git a/oidc4vp/migrations/0001_initial.py b/oidc4vp/migrations/0001_initial.py
deleted file mode 100644
index b29aed0..0000000
--- a/oidc4vp/migrations/0001_initial.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Generated by Django 4.2.5 on 2024-01-18 11:32
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-import oidc4vp.models
-
-
-class Migration(migrations.Migration):
- initial = True
-
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ]
-
- operations = [
- migrations.CreateModel(
- name='Authorization',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- (
- 'code',
- models.CharField(default=oidc4vp.models.set_code, max_length=24),
- ),
- ('code_used', models.BooleanField(default=False)),
- ('created', models.DateTimeField(auto_now=True)),
- ('presentation_definition', models.CharField(max_length=250)),
- ],
- ),
- migrations.CreateModel(
- name='Organization',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('name', models.CharField(max_length=250)),
- (
- 'client_id',
- models.CharField(
- default=oidc4vp.models.set_client_id, max_length=24, unique=True
- ),
- ),
- (
- 'client_secret',
- models.CharField(
- default=oidc4vp.models.set_client_secret, max_length=48
- ),
- ),
- ('my_client_id', models.CharField(max_length=24)),
- ('my_client_secret', models.CharField(max_length=48)),
- (
- 'response_uri',
- models.URLField(
- help_text='Url where to send the verificable presentation',
- max_length=250,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name='OAuth2VPToken',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('created', models.DateTimeField(auto_now=True)),
- ('result_verify', models.CharField(max_length=255)),
- ('vp_token', models.TextField()),
- (
- 'authorization',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.SET_NULL,
- related_name='vp_tokens',
- to='oidc4vp.authorization',
- ),
- ),
- (
- 'organization',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='vp_tokens',
- to='oidc4vp.organization',
- ),
- ),
- (
- 'user',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='vp_tokens',
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.AddField(
- model_name='authorization',
- name='organization',
- field=models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='authorizations',
- to='oidc4vp.organization',
- ),
- ),
- migrations.AddField(
- model_name='authorization',
- name='user',
- field=models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ]
diff --git a/promotion/migrations/0001_initial.py b/promotion/migrations/0001_initial.py
deleted file mode 100644
index cabebc3..0000000
--- a/promotion/migrations/0001_initial.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Generated by Django 4.2.5 on 2024-01-18 11:32
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
- initial = True
-
- dependencies = [
- ('oidc4vp', '0001_initial'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='Promotion',
- fields=[
- (
- 'id',
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name='ID',
- ),
- ),
- ('name', models.CharField(max_length=250)),
- (
- 'discount',
- models.PositiveSmallIntegerField(
- choices=[(1, 'Financial vulnerability')]
- ),
- ),
- (
- 'authorize',
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name='promotions',
- to='oidc4vp.authorization',
- ),
- ),
- ],
- ),
- ]
diff --git a/requirements.txt b/requirements.txt
index c5f9def..c7103f4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -26,4 +26,4 @@ uharfbuzz==0.38.0
fontTools==4.47.0
weasyprint==60.2
ujson==5.9.0
-didkit-0.3.2-cp311-cp311-manylinux_2_34_x86_64.whl
+./didkit-0.3.2-cp311-cp311-manylinux_2_34_x86_64.whl
diff --git a/utils/idhub_ssikit/__init__.py b/utils/idhub_ssikit/__init__.py
index 3521eba..85e6e2f 100644
--- a/utils/idhub_ssikit/__init__.py
+++ b/utils/idhub_ssikit/__init__.py
@@ -2,6 +2,7 @@ import asyncio
import datetime
import didkit
import json
+import urllib
import jinja2
from django.template.backends.django import Template
from django.template.loader import get_template
@@ -29,7 +30,8 @@ def webdid_from_controller_key(key):
keydid = keydid_from_controller_key(key) # "did:key:<...>"
pubkeyid = keydid.rsplit(":")[-1] # <...>
document = json.loads(asyncio.run(resolve_keydid(keydid))) # Documento DID en terminos "key"
- webdid_url = f"did:web:{settings.DOMAIN}:did-registry:{pubkeyid}" # nueva URL: "did:web:idhub.pangea.org:<...>"
+ domain = urllib.parse.urlencode({"domain": settings.DOMAIN})[7:]
+ webdid_url = f"did:web:{domain}:did-registry:{pubkeyid}" # nueva URL: "did:web:idhub.pangea.org:<...>"
webdid_url_owner = webdid_url + "#owner"
# Reemplazamos los campos del documento DID necesarios:
document["id"] = webdid_url