154 lines
6.2 KiB
Python
154 lines
6.2 KiB
Python
|
import base64
|
||
|
from io import BytesIO
|
||
|
|
||
|
from cryptography.hazmat.primitives import hashes
|
||
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||
|
from cryptography.hazmat.primitives import serialization
|
||
|
from cryptography.fernet import Fernet, InvalidToken
|
||
|
|
||
|
from django.conf import settings
|
||
|
from django.contrib import messages
|
||
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||
|
from django.core.exceptions import PermissionDenied
|
||
|
from django.core.files.base import ContentFile
|
||
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||
|
from django.shortcuts import get_object_or_404, reverse
|
||
|
from django.template.loader import render_to_string
|
||
|
from django.utils import timezone
|
||
|
from django.utils.text import slugify
|
||
|
from django.views.generic import FormView, TemplateView, View
|
||
|
|
||
|
from aemo.models import Famille
|
||
|
from aemo.utils import is_ajax
|
||
|
from .models import Archive
|
||
|
from .pdf import ArchivePdf
|
||
|
|
||
|
from .forms import ArchiveFilterForm, ArchiveKeyUploadForm
|
||
|
|
||
|
|
||
|
class ArchiveCreateView(View):
|
||
|
|
||
|
def post(self, request, *args, **kwargs):
|
||
|
unite = 'aemo'
|
||
|
temp = BytesIO()
|
||
|
|
||
|
famille = get_object_or_404(Famille, pk=kwargs['pk'], archived_at__isnull=True)
|
||
|
intervenants_list = '/'.join([f"{interv.nom} {interv.prenom[0].upper()}."
|
||
|
for interv in famille.suivi.intervenants.all()])
|
||
|
ope_list = famille.suivi.ope_referents
|
||
|
motif_fin = famille.suivi.get_motif_fin_suivi_display()
|
||
|
pdf = ArchivePdf(temp, famille)
|
||
|
|
||
|
if not famille.can_be_archived(self.request.user):
|
||
|
raise PermissionDenied("Vous n'avez pas les droits nécessaires pour accéder à cette page.")
|
||
|
|
||
|
famille.archived_at = timezone.now()
|
||
|
pdf.produce()
|
||
|
filename = f"{unite}/{pdf.get_filename()}"
|
||
|
temp.seek(0)
|
||
|
pdf = temp.read()
|
||
|
|
||
|
# Create a symmetric Fernet key to encrypt the PDF, and encrypt that key with asymmetric RSA key.
|
||
|
key = Fernet.generate_key()
|
||
|
fernet = Fernet(key)
|
||
|
pdf_crypted = fernet.encrypt(pdf)
|
||
|
|
||
|
with open(settings.CRNE_RSA_PUBLIC_KEY, "rb") as key_file:
|
||
|
public_key = serialization.load_ssh_public_key(key_file.read())
|
||
|
padd = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)
|
||
|
fernet_crypted = public_key.encrypt(key, padding=padd)
|
||
|
|
||
|
nom_famille = famille.nom
|
||
|
arch = Archive.objects.create(
|
||
|
nom=nom_famille,
|
||
|
unite=unite,
|
||
|
intervenant=intervenants_list,
|
||
|
ope=", ".join([ope.nom_prenom for ope in ope_list]),
|
||
|
motif_fin=motif_fin,
|
||
|
date_debut=famille.suivi.date_debut_suivi,
|
||
|
date_fin=famille.suivi.date_fin_suivi,
|
||
|
key=base64.b64encode(fernet_crypted).decode(),
|
||
|
pdf=None
|
||
|
)
|
||
|
arch.pdf.save(filename, ContentFile(pdf_crypted))
|
||
|
famille.archived_at = timezone.now()
|
||
|
famille.save()
|
||
|
|
||
|
famille.anonymiser()
|
||
|
|
||
|
if is_ajax(request):
|
||
|
return JsonResponse({'id': famille.pk}, safe=True)
|
||
|
|
||
|
messages.success(request, f"La famille «{nom_famille}» a bien été archivée.")
|
||
|
return HttpResponseRedirect(reverse("suivis-termines"))
|
||
|
|
||
|
|
||
|
class ArchiveListView(TemplateView):
|
||
|
template_name = 'archive/list.html'
|
||
|
model = Archive
|
||
|
|
||
|
def dispatch(self, request, *args, **kwargs):
|
||
|
self.unite = self.kwargs['unite']
|
||
|
self.filter_form = ArchiveFilterForm(data=request.GET or None)
|
||
|
return super().dispatch(request, *args, **kwargs)
|
||
|
|
||
|
def get(self, request, *args, **kwargs):
|
||
|
if is_ajax(request) and self.unite == 'aemo':
|
||
|
if self.filter_form.is_bound and self.filter_form.is_valid():
|
||
|
archives = self.filter_form.filter(Archive.objects.filter(unite=self.unite))
|
||
|
else:
|
||
|
archives = Archive.objects.none()
|
||
|
response = render_to_string(
|
||
|
template_name='archive/list_partial.html',
|
||
|
context={
|
||
|
'archives': archives,
|
||
|
'can_download': request.user.has_perm('aemo.can_archive'),
|
||
|
}
|
||
|
)
|
||
|
return JsonResponse(response, safe=False)
|
||
|
return super().get(request, *args, **kwargs)
|
||
|
|
||
|
def get_context_data(self, *args, **kwargs):
|
||
|
return {
|
||
|
**super().get_context_data(*args, **kwargs),
|
||
|
'unite': self.unite,
|
||
|
'form': self.filter_form,
|
||
|
'archives': Archive.objects.filter(unite=self.unite),
|
||
|
'can_download': self.request.user.has_perm('aemo.can_archive'),
|
||
|
}
|
||
|
|
||
|
|
||
|
class ArchiveDecryptView(PermissionRequiredMixin, FormView):
|
||
|
form_class = ArchiveKeyUploadForm
|
||
|
template_name = 'archive/key_upload.html'
|
||
|
permission_required = 'aemo.can_archive'
|
||
|
|
||
|
def form_valid(self, form):
|
||
|
arch = get_object_or_404(Archive, pk=self.kwargs['pk'])
|
||
|
try:
|
||
|
with open(arch.pdf.path, "rb") as fh:
|
||
|
pdf_crypted = fh.read()
|
||
|
except OSError as err:
|
||
|
messages.error(self.request, f"Erreur lors de la lecture du document ({str(err)})")
|
||
|
return HttpResponseRedirect(reverse('archive-list', args=[arch.unite]))
|
||
|
|
||
|
try:
|
||
|
private_key_file = self.request.FILES['file'].read()
|
||
|
private_key = serialization.load_pem_private_key(private_key_file, password=None)
|
||
|
padd = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)
|
||
|
sim_key = private_key.decrypt(base64.b64decode(arch.key), padding=padd)
|
||
|
|
||
|
fernet = Fernet(sim_key)
|
||
|
pdf_content = fernet.decrypt(pdf_crypted)
|
||
|
except ValueError as err:
|
||
|
messages.error(self.request, f"Erreur lors de la lecture de la clé ({str(err)})")
|
||
|
return HttpResponseRedirect(reverse('archive-list', args=[arch.unite]))
|
||
|
except InvalidToken:
|
||
|
messages.error(self.request, "Erreur lors du déchiffrement")
|
||
|
return HttpResponseRedirect(reverse('archive-list', args=[arch.unite]))
|
||
|
|
||
|
filename = f"{slugify(arch.nom)}.pdf"
|
||
|
response = HttpResponse(pdf_content, content_type='application/pdf')
|
||
|
response['Content-Disposition'] = "attachment; filename=%s" % filename
|
||
|
return response
|