From 0247c5007dac70ee1d8fdda2c7e7f9ee00643279 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 20 Feb 2024 17:50:45 +0100 Subject: [PATCH] new encriptation system of sensible datas --- idhub/admin/forms.py | 45 ++++++++-- idhub/admin/views.py | 37 +++++--- idhub/management/commands/initial_datas.py | 19 ++--- idhub/mixins.py | 19 ++++- idhub/models.py | 84 ++++++++----------- .../idhub/admin/issue_credentials.html | 2 +- idhub/templates/idhub/user/credential.html | 2 +- idhub/urls.py | 4 + idhub/user/forms.py | 4 +- idhub/user/views.py | 51 +++++------ idhub/views.py | 23 ++--- idhub_auth/models.py | 56 +++++++------ 12 files changed, 192 insertions(+), 154 deletions(-) diff --git a/idhub/admin/forms.py b/idhub/admin/forms.py index aa453ce..fd57e64 100644 --- a/idhub/admin/forms.py +++ b/idhub/admin/forms.py @@ -1,23 +1,19 @@ -import csv import json -import copy import base64 import jsonschema import pandas as pd -from pyhanko.sign import signers - +from nacl.exceptions import CryptoError from django import forms from django.core.cache import cache from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError -from utils import credtools, certs +from utils import certs from idhub.models import ( DID, File_datas, Membership, Schemas, - Service, UserRol, VerificableCredential, ) @@ -51,6 +47,37 @@ class TermsConditionsForm2(forms.Form): return +class EncryptionKeyForm(forms.Form): + key = forms.CharField( + label=_("Key for encrypt the secrets of all system"), + required=True + ) + + def clean(self): + data = self.cleaned_data + self._key = data["key"] + if not DID.objects.exists(): + return data + + did = DID.objects.first() + cache.set("KEY_DIDS", self._key, None) + try: + did.get_key_material() + except CryptoError: + cache.set("KEY_DIDS", None) + txt = _("Key no valid!") + raise ValidationError(txt) + + return data + + def save(self, commit=True): + + if commit: + cache.set("KEY_DIDS", self._key, None) + + return + + class TermsConditionsForm(forms.Form): accept_privacy = forms.BooleanField( widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}), @@ -133,7 +160,7 @@ class ImportForm(forms.Form): self.fields['did'].choices = [ (x.did, x.label) for x in dids.filter(eidas1=False) ] - self.fields['schema'].choices = [ + self.fields['schema'].choices = [(0, _('Select one'))] + [ (x.id, x.name) for x in Schemas.objects.filter() ] if dids.filter(eidas1=True).exists(): @@ -197,6 +224,9 @@ class ImportForm(forms.Form): if not data_pd: self.exception("This file is empty!") + if not self._schema: + return data + for n in range(df.last_valid_index()+1): row = {} for k in data_pd.keys(): @@ -382,7 +412,6 @@ class ImportCertificateForm(forms.Form): return data def new_did(self): - cert = self.pfx_file keys = { "cert": base64.b64encode(self.pfx_file).decode('utf-8'), "passphrase": self._pss diff --git a/idhub/admin/views.py b/idhub/admin/views.py index 25ac28d..8a9bb63 100644 --- a/idhub/admin/views.py +++ b/idhub/admin/views.py @@ -1,9 +1,6 @@ import os import json -import logging -import pandas as pd from pathlib import Path -from jsonschema import validate from smtplib import SMTPException from django_tables2 import SingleTableView @@ -18,7 +15,6 @@ from django.views.generic.edit import ( UpdateView, ) from django.shortcuts import get_object_or_404, redirect -from django.core.cache import cache from django.urls import reverse_lazy from django.http import HttpResponse from django.contrib import messages @@ -28,12 +24,13 @@ from idhub_auth.forms import ProfileForm from idhub.mixins import AdminView, Http403 from idhub.email.views import NotifyActivateUserByEmail from idhub.admin.forms import ( + EncryptionKeyForm, + ImportCertificateForm, ImportForm, MembershipForm, TermsConditionsForm, SchemaForm, - UserRolForm, - ImportCertificateForm, + UserRolForm ) from idhub.admin.tables import ( DashboardTable, @@ -79,7 +76,27 @@ class TermsAndConditionsView(AdminView, FormView): return kwargs def form_valid(self, form): - user = form.save() + form.save() + return super().form_valid(form) + + +class EncryptionKeyView(AdminView, FormView): + template_name = "idhub/admin/encryption_key.html" + title = _('Encryption Key') + section = "" + subtitle = _('Encryption Key') + icon = 'bi bi-key' + form_class = EncryptionKeyForm + success_url = reverse_lazy('idhub:admin_dashboard') + + def get(self, request, *args, **kwargs): + if self.admin_validated: + return redirect(self.success_url) + + return super().get(request, *args, **kwargs) + + def form_valid(self, form): + form.save() return super().form_valid(form) @@ -649,7 +666,7 @@ class CredentialJsonView(Credentials): VerificableCredential, pk=pk, ) - response = HttpResponse(self.object.data, content_type="application/json") + response = HttpResponse(self.object.get_data(), content_type="application/json") response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json") return response @@ -730,7 +747,7 @@ class DidRegisterView(Credentials, CreateView): def form_valid(self, form): form.instance.user = self.request.user - form.instance.set_did(cache.get("KEY_DIDS")) + form.instance.set_did() form.save() messages.success(self.request, _('DID created successfully')) Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance) @@ -752,7 +769,7 @@ class DidEditView(Credentials, UpdateView): return super().get(request, *args, **kwargs) def form_valid(self, form): - user = form.save() + form.save() messages.success(self.request, _('DID updated successfully')) return super().form_valid(form) diff --git a/idhub/management/commands/initial_datas.py b/idhub/management/commands/initial_datas.py index e8abf19..15f74ea 100644 --- a/idhub/management/commands/initial_datas.py +++ b/idhub/management/commands/initial_datas.py @@ -23,6 +23,8 @@ class Command(BaseCommand): def handle(self, *args, **kwargs): ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org') ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234') + KEY_DIDS = config('KEY_DIDS', '1234') + cache.set("KEY_DIDS", KEY_DIDS, None) self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD) if settings.CREATE_TEST_USERS: @@ -43,21 +45,17 @@ class Command(BaseCommand): def create_admin_users(self, email, password): su = User.objects.create_superuser(email=email, password=password) - su.set_encrypted_sensitive_data(password) + su.set_encrypted_sensitive_data() su.save() - key = su.decrypt_sensitive_data(password) - key_dids = {su.id: key} - cache.set("KEY_DIDS", key_dids, None) - self.create_defaults_dids(su, key) + self.create_defaults_dids(su) def create_users(self, email, password): u = User.objects.create(email=email, password=password) u.set_password(password) - u.set_encrypted_sensitive_data(password) + u.set_encrypted_sensitive_data() u.save() - key = u.decrypt_sensitive_data(password) - self.create_defaults_dids(u, key) + self.create_defaults_dids(u) def create_organizations(self, name, url): @@ -72,9 +70,10 @@ class Command(BaseCommand): org1.my_client_secret = org2.client_secret org1.save() org2.save() - def create_defaults_dids(self, u, password): + + def create_defaults_dids(self, u): did = DID(label="Default", user=u, type=DID.Types.WEB) - did.set_did(password) + did.set_did() did.save() def create_schemas(self): diff --git a/idhub/mixins.py b/idhub/mixins.py index b2b3fbe..ad1379b 100644 --- a/idhub/mixins.py +++ b/idhub/mixins.py @@ -12,8 +12,8 @@ class Http403(PermissionDenied): default_detail = _('Permission denied. User is not authenticated') default_code = 'forbidden' - def __init__(self, detail=None, code=None): - if detail is not None: + def __init__(self, details=None, code=None): + if details is not None: self.detail = details or self.default_details if code is not None: self.code = code or self.default_code @@ -22,15 +22,30 @@ class Http403(PermissionDenied): class UserView(LoginRequiredMixin): login_url = "/login/" wallet = False + admin_validated = False path_terms = [ 'admin_terms_and_conditions', 'user_terms_and_conditions', 'user_gdpr', + 'user_waiting', + 'user_waiting', + 'encryption_key', ] def get(self, request, *args, **kwargs): self.admin_validated = cache.get("KEY_DIDS") response = super().get(request, *args, **kwargs) + + if not self.admin_validated: + actual_path = resolve(self.request.path).url_name + if not self.request.user.is_admin: + if actual_path != 'user_waiting': + return redirect(reverse_lazy("idhub:user_waiting")) + + if self.request.user.is_admin: + if actual_path != 'encryption_key': + return redirect(reverse_lazy("idhub:encryption_key")) + url = self.check_gdpr() return url or response diff --git a/idhub/models.py b/idhub/models.py index ae61c56..7d6a1c6 100644 --- a/idhub/models.py +++ b/idhub/models.py @@ -9,7 +9,6 @@ from django.conf import settings from django.core.cache import cache from django.template.loader import get_template from django.utils.translation import gettext_lazy as _ -from nacl import secret from utils.idhub_ssikit import ( generate_did_controller_key, @@ -34,26 +33,27 @@ class Event(models.Model): EV_DID_CREATED = 9, "DID created" EV_DID_DELETED = 10, "DID deleted" EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user" - EV_CREDENTIAL_DELETED = 12, "Credential deleted" - EV_CREDENTIAL_ISSUED_FOR_USER = 13, "Credential issued for user" - EV_CREDENTIAL_ISSUED = 14, "Credential issued" - EV_CREDENTIAL_PRESENTED_BY_USER = 15, "Credential presented by user" - EV_CREDENTIAL_PRESENTED = 16, "Credential presented" - EV_CREDENTIAL_ENABLED = 17, "Credential enabled" - EV_CREDENTIAL_CAN_BE_REQUESTED = 18, "Credential available" - EV_CREDENTIAL_REVOKED_BY_ADMIN = 19, "Credential revoked by admin" - EV_CREDENTIAL_REVOKED = 20, "Credential revoked" - EV_ROLE_CREATED_BY_ADMIN = 21, "Role created by admin" - EV_ROLE_MODIFIED_BY_ADMIN = 22, "Role modified by admin" - EV_ROLE_DELETED_BY_ADMIN = 23, "Role deleted by admin" - EV_SERVICE_CREATED_BY_ADMIN = 24, "Service created by admin" - EV_SERVICE_MODIFIED_BY_ADMIN = 25, "Service modified by admin" - EV_SERVICE_DELETED_BY_ADMIN = 26, "Service deleted by admin" - EV_ORG_DID_CREATED_BY_ADMIN = 27, "Organisational DID created by admin" - EV_ORG_DID_DELETED_BY_ADMIN = 28, "Organisational DID deleted by admin" - EV_USR_DEACTIVATED_BY_ADMIN = 29, "User deactivated" - EV_USR_ACTIVATED_BY_ADMIN = 30, "User activated" - EV_USR_SEND_VP = 31, "User send Verificable Presentation" + EV_CREDENTIAL_DELETED_BY_ADMIN = 12, "Credential deleted by admin" + EV_CREDENTIAL_DELETED = 13, "Credential deleted" + EV_CREDENTIAL_ISSUED_FOR_USER = 14, "Credential issued for user" + EV_CREDENTIAL_ISSUED = 15, "Credential issued" + EV_CREDENTIAL_PRESENTED_BY_USER = 16, "Credential presented by user" + EV_CREDENTIAL_PRESENTED = 17, "Credential presented" + EV_CREDENTIAL_ENABLED = 18, "Credential enabled" + EV_CREDENTIAL_CAN_BE_REQUESTED = 19, "Credential available" + EV_CREDENTIAL_REVOKED_BY_ADMIN = 20, "Credential revoked by admin" + EV_CREDENTIAL_REVOKED = 21, "Credential revoked" + EV_ROLE_CREATED_BY_ADMIN = 22, "Role created by admin" + EV_ROLE_MODIFIED_BY_ADMIN = 23, "Role modified by admin" + EV_ROLE_DELETED_BY_ADMIN = 24, "Role deleted by admin" + EV_SERVICE_CREATED_BY_ADMIN = 25, "Service created by admin" + EV_SERVICE_MODIFIED_BY_ADMIN = 26, "Service modified by admin" + EV_SERVICE_DELETED_BY_ADMIN = 27, "Service deleted by admin" + EV_ORG_DID_CREATED_BY_ADMIN = 28, "Organisational DID created by admin" + EV_ORG_DID_DELETED_BY_ADMIN = 29, "Organisational DID deleted by admin" + EV_USR_DEACTIVATED_BY_ADMIN = 30, "User deactivated" + EV_USR_ACTIVATED_BY_ADMIN = 31, "User activated" + EV_USR_SEND_VP = 32, "User send Verificable Presentation" created = models.DateTimeField(_("Date"), auto_now=True) message = models.CharField(_("Description"), max_length=350) @@ -99,9 +99,8 @@ class Event(models.Model): @classmethod def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user): msg = _("The user '{username}' has request the update of the following information: ") - msg += "['field1':'value1', 'field2':'value2'>,...]".format( - username=user.username, - ) + msg += "['field1':'value1', 'field2':'value2'>,...]" + msg = msg.format(username=user.username) cls.objects.create( type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER, message=msg, @@ -444,11 +443,11 @@ class DID(models.Model): # JSON-serialized DID document didweb_document = models.TextField() - def get_key_material(self, password): - return self.user.decrypt_data(self.key_material, password) + def get_key_material(self): + return self.user.decrypt_data(self.key_material) - def set_key_material(self, value, password): - self.key_material = self.user.encrypt_data(value, password) + def set_key_material(self, value): + self.key_material = self.user.encrypt_data(value) @property def is_organization_did(self): @@ -456,9 +455,9 @@ class DID(models.Model): return True return False - def set_did(self, password): + def set_did(self): new_key_material = generate_did_controller_key() - self.set_key_material(new_key_material, password) + self.set_key_material(new_key_material) if self.type == self.Types.KEY: self.did = keydid_from_controller_key(new_key_material) @@ -621,17 +620,14 @@ class VerificableCredential(models.Model): return True return False - def get_data(self, password): + def get_data(self): if not self.data: return "" - if self.eidas1_did: - return self.data - - return self.user.decrypt_data(self.data, password) + return self.user.decrypt_data(self.data) - def set_data(self, value, password): - self.data = self.user.encrypt_data(value, password) + def set_data(self, value): + self.data = self.user.encrypt_data(value) def get_description(self): return self.schema._description or '' @@ -652,32 +648,24 @@ class VerificableCredential(models.Model): data = json.loads(self.csv_data).items() return data - def issue(self, did, password, domain=settings.DOMAIN.strip("/")): + def issue(self, did, domain=settings.DOMAIN.strip("/")): if self.status == self.Status.ISSUED: return self.subject_did = did self.issued_on = datetime.datetime.now().astimezone(pytz.utc) - issuer_pass = cache.get("KEY_DIDS") - # issuer_pass = self.user.decrypt_data( - # cache.get("KEY_DIDS"), - # settings.SECRET_KEY, - # ) # hash of credential without sign self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest() data = sign_credential( self.render(domain), - self.issuer_did.get_key_material(issuer_pass) + self.issuer_did.get_key_material() ) valid, reason = verify_credential(data) if not valid: return - if self.eidas1_did: - self.data = data - else: - self.data = self.user.encrypt_data(data, password) + self.data = self.user.encrypt_data(data) self.status = self.Status.ISSUED diff --git a/idhub/templates/idhub/admin/issue_credentials.html b/idhub/templates/idhub/admin/issue_credentials.html index ac93171..3c29289 100644 --- a/idhub/templates/idhub/admin/issue_credentials.html +++ b/idhub/templates/idhub/admin/issue_credentials.html @@ -38,7 +38,7 @@ {% trans 'Issuance date' %}:
- {{ object.issuer_on|default_if_none:"" }} + {{ object.issued_on|default_if_none:"" }}
diff --git a/idhub/templates/idhub/user/credential.html b/idhub/templates/idhub/user/credential.html index 1ee66a4..415c280 100644 --- a/idhub/templates/idhub/user/credential.html +++ b/idhub/templates/idhub/user/credential.html @@ -25,7 +25,7 @@ {% trans 'Issuance date' %}:
- {{ object.issuer_on|default_if_none:"" }} + {{ object.issued_on|default_if_none:"" }}
diff --git a/idhub/urls.py b/idhub/urls.py index 30338b3..d0230c9 100644 --- a/idhub/urls.py +++ b/idhub/urls.py @@ -88,6 +88,9 @@ urlpatterns = [ path('user/terms/', views_user.TermsAndConditionsView.as_view(), name='user_terms_and_conditions'), + path('waiting/', views_user.WaitingView.as_view(), + name='user_waiting'), + # Admin path('admin/dashboard/', views_admin.DashboardView.as_view(), name='admin_dashboard'), @@ -173,6 +176,7 @@ urlpatterns = [ name='admin_terms_and_conditions'), path('admin/import/new', views_admin.ImportAddView.as_view(), name='admin_import_add'), + path('admin/enc/', views_admin.EncryptionKeyView.as_view(), name='encryption_key'), path('admin/auth/', views_admin.DobleFactorAuthView.as_view(), name='admin_2fauth'), path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'), diff --git a/idhub/user/forms.py b/idhub/user/forms.py index 9561eb7..1102e9a 100644 --- a/idhub/user/forms.py +++ b/idhub/user/forms.py @@ -81,7 +81,6 @@ class RequestCredentialForm(forms.Form): self.user = kwargs.pop('user', None) self.lang = kwargs.pop('lang', None) self._domain = kwargs.pop('domain', None) - self.password = kwargs.pop('password', None) super().__init__(*args, **kwargs) self.fields['did'].choices = [ (x.did, x.label) for x in DID.objects.filter(user=self.user) @@ -109,8 +108,7 @@ class RequestCredentialForm(forms.Form): did = did[0] cred = cred[0] try: - if self.password: - cred.issue(did, self.password, domain=self._domain) + cred.issue(did, domain=self._domain) except Exception: return diff --git a/idhub/user/views.py b/idhub/user/views.py index 27c8f77..a31fc63 100644 --- a/idhub/user/views.py +++ b/idhub/user/views.py @@ -161,10 +161,25 @@ class TermsAndConditionsView(UserView, FormView): return kwargs def form_valid(self, form): - user = form.save() + form.save() return super().form_valid(form) +class WaitingView(UserView, TemplateView): + template_name = "idhub/user/waiting.html" + title = _("Comunication with admin") + subtitle = _('Service temporary close') + section = "" + icon = 'bi bi-file-earmark-medical' + success_url = reverse_lazy('idhub:user_dashboard') + + def get(self, request, *args, **kwargs): + if cache.get("KEY_DIDS"): + return redirect(self.success_url) + return super().get(request, *args, **kwargs) + + + class CredentialView(MyWallet, TemplateView): template_name = "idhub/user/credential.html" subtitle = _('Credential') @@ -194,7 +209,8 @@ class CredentialPdfView(MyWallet, TemplateView): file_name = "certificate.pdf" def get(self, request, *args, **kwargs): - self.admin_validated = cache.get("KEY_DIDS") + if not self.admin_validated: + return redirect(reverse_lazy('idhub:user_dashboard')) pk = kwargs['pk'] self.user = self.request.user self.object = get_object_or_404( @@ -282,10 +298,9 @@ class CredentialPdfView(MyWallet, TemplateView): def get_pfx_data(self): did = self.object.eidas1_did - pw = self.admin_validated - if not did or not pw: + if not did: return None, None - key_material = json.loads(did.get_key_material(pw)) + key_material = json.loads(did.get_key_material()) cert = key_material.get("cert") passphrase = key_material.get("passphrase") if cert and passphrase: @@ -337,14 +352,7 @@ class CredentialJsonView(MyWallet, TemplateView): pk=pk, user=self.request.user ) - pass_enc = self.request.session.get("key_did") - data = "" - if pass_enc: - user_pass = self.request.user.decrypt_data( - pass_enc, - self.request.user.password+self.request.session._session_key - ) - data = self.object.get_data(user_pass) + data = self.object.get_data() response = HttpResponse(data, content_type="application/json") response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json") return response @@ -383,15 +391,6 @@ class CredentialsRequestView(MyWallet, FormView): kwargs['lang'] = self.request.LANGUAGE_CODE domain = "{}://{}".format(self.request.scheme, self.request.get_host()) kwargs['domain'] = domain - pass_enc = self.request.session.get("key_did") - if pass_enc: - user_pass = self.request.user.decrypt_data( - pass_enc, - self.request.user.password+self.request.session._session_key - ) - else: - pass_enc = None - kwargs['password'] = user_pass return kwargs def form_valid(self, form): @@ -468,11 +467,7 @@ class DidRegisterView(MyWallet, CreateView): def form_valid(self, form): form.instance.user = self.request.user - pw = self.request.user.decrypt_data( - self.request.session.get("key_did"), - self.request.user.password+self.request.session._session_key - ) - form.instance.set_did(pw) + form.instance.set_did() form.save() messages.success(self.request, _('DID created successfully')) @@ -496,7 +491,7 @@ class DidEditView(MyWallet, UpdateView): return super().get(request, *args, **kwargs) def form_valid(self, form): - user = form.save() + form.save() messages.success(self.request, _('DID updated successfully')) return super().form_valid(form) diff --git a/idhub/views.py b/idhub/views.py index 0d0ee68..8cdecb5 100644 --- a/idhub/views.py +++ b/idhub/views.py @@ -18,7 +18,6 @@ from django.http import HttpResponseRedirect, HttpResponse, Http404 from idhub.models import DID, VerificableCredential from idhub.email.views import NotifyActivateUserByEmail -from trustchain_idhub import settings logger = logging.getLogger(__name__) @@ -46,30 +45,20 @@ class LoginView(auth_views.LoginView): def form_valid(self, form): user = form.get_user() - password = form.cleaned_data.get("password") auth_login(self.request, user) - sensitive_data_encryption_key = user.decrypt_sensitive_data(password) + if user.is_anonymous: + return redirect(reverse_lazy("idhub:login")) - if not user.is_anonymous and user.is_admin: - admin_dashboard = reverse_lazy('idhub:admin_dashboard') - self.extra_context['success_url'] = admin_dashboard - # encryption_key = user.encrypt_data( - # sensitive_data_encryption_key, - # settings.SECRET_KEY - # ) - # cache.set("KEY_DIDS", encryption_key, None) - cache.set("KEY_DIDS", sensitive_data_encryption_key, None) + if user.is_admin: if settings.ENABLE_2FACTOR_AUTH: self.request.session["2fauth"] = str(uuid.uuid4()) return redirect(reverse_lazy('idhub:confirm_send_2f')) - self.request.session["key_did"] = user.encrypt_data( - sensitive_data_encryption_key, - user.password+self.request.session._session_key - ) + admin_dashboard = reverse_lazy('idhub:admin_dashboard') + self.extra_context['success_url'] = admin_dashboard - return HttpResponseRedirect(self.extra_context['success_url']) + return redirect(self.extra_context['success_url']) class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): diff --git a/idhub_auth/models.py b/idhub_auth/models.py index ca4b422..49a6281 100644 --- a/idhub_auth/models.py +++ b/idhub_auth/models.py @@ -1,7 +1,7 @@ import nacl import base64 -from nacl import pwhash +from nacl import pwhash, secret from django.db import models from django.core.cache import cache from django.utils.translation import gettext_lazy as _ @@ -95,21 +95,24 @@ class User(AbstractBaseUser): roles.append(r.name) return ", ".join(set(roles)) - def derive_key_from_password(self, password): + def derive_key_from_password(self, password=None): + if not password: + password = cache.get("KEY_DIDS").encode('utf-8') + kdf = pwhash.argon2i.kdf ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE return kdf( - nacl.secret.SecretBox.KEY_SIZE, + secret.SecretBox.KEY_SIZE, password, self.get_salt(), opslimit=ops, memlimit=mem ) - def decrypt_sensitive_data(self, password, data=None): - sb_key = self.derive_key_from_password(password.encode('utf-8')) - sb = nacl.secret.SecretBox(sb_key) + def decrypt_sensitive_data(self, data=None): + sb_key = self.derive_key_from_password() + sb = secret.SecretBox(sb_key) if not data: data = self.get_encrypted_sensitive_data() if not isinstance(data, bytes): @@ -117,9 +120,9 @@ class User(AbstractBaseUser): return sb.decrypt(data).decode('utf-8') - def encrypt_sensitive_data(self, password, data): - sb_key = self.derive_key_from_password(password.encode('utf-8')) - sb = nacl.secret.SecretBox(sb_key) + def encrypt_sensitive_data(self, data): + sb_key = self.derive_key_from_password() + sb = secret.SecretBox(sb_key) if not isinstance(data, bytes): data = data.encode('utf-8') @@ -134,32 +137,33 @@ class User(AbstractBaseUser): def get_encrypted_sensitive_data(self): return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8')) - def set_encrypted_sensitive_data(self, password): + def set_encrypted_sensitive_data(self): key = base64.b64encode(nacl.utils.random(64)) self.set_salt() - key_crypted = self.encrypt_sensitive_data(password, key) + key_crypted = self.encrypt_sensitive_data(key) self.encrypted_sensitive_data = key_crypted - def encrypt_data(self, data, password): - sb = self.get_secret_box(password) + def encrypt_data(self, data): + sb = self.get_secret_box() value_enc = sb.encrypt(data.encode('utf-8')) return base64.b64encode(value_enc).decode('utf-8') - def decrypt_data(self, data, password): - sb = self.get_secret_box(password) + def decrypt_data(self, data): + sb = self.get_secret_box() value = base64.b64decode(data.encode('utf-8')) return sb.decrypt(value).decode('utf-8') - def get_secret_box(self, password): - pw = base64.b64decode(password.encode('utf-8')*4) - sb_key = self.derive_key_from_password(pw) - return nacl.secret.SecretBox(sb_key) + def get_secret_box(self): + sb_key = self.derive_key_from_password() + return secret.SecretBox(sb_key) - def change_password(self, old_password, new_password): - sensitive_data = self.decrypt_sensitive_data(old_password) - self.encrypted_sensitive_data = self.encrypt_sensitive_data( - new_password, - sensitive_data - ) - self.set_password(new_password) + def change_password_key(self, new_password): + data = self.decrypt_sensitive_data() + sb_key = self.derive_key_from_password(new_password) + sb = secret.SecretBox(sb_key) + if not isinstance(data, bytes): + data = data.encode('utf-8') + + encrypted_data = base64.b64encode(sb.encrypt(data)).decode('utf-8') + self.encrypted_sensitive_data = encrypted_data