diff --git a/preferences/__init__.py b/preferences/__init__.py index e895e295..c287fce8 100644 --- a/preferences/__init__.py +++ b/preferences/__init__.py @@ -1,2 +1,28 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# Copyright © 2018 Maël Kervella +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +"""preferences +The app in charge of storing all the preferences for the local installation +""" from .acl import * diff --git a/preferences/aes_field.py b/preferences/aes_field.py index ce90e1f4..1d3ffa54 100644 --- a/preferences/aes_field.py +++ b/preferences/aes_field.py @@ -1,3 +1,34 @@ +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# Copyright © 2018 Maël Kervella +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# App de gestion des machines pour re2o +# Gabriel Détraz, Augustin Lemesle +# Gplv2 +"""preferences.aes_field +Module defining a AESEncryptedField object that can be used in forms +to handle the use of properly encrypting and decrypting AES keys +""" + import string import binascii from random import choice @@ -10,10 +41,13 @@ EOD = '`%EofD%`' # This should be something that will not occur in strings def genstring(length=16, chars=string.printable): + """ Generate a random string of length `length` and composed of + the characters in `chars` """ return ''.join([choice(chars) for i in range(length)]) def encrypt(key, s): + """ AES Encrypt a secret `s` with the key `key` """ obj = AES.new(key) datalength = len(s) + len(EOD) if datalength < 16: @@ -25,12 +59,15 @@ def encrypt(key, s): def decrypt(key, s): + """ AES Decrypt a secret `s` with the key `key` """ obj = AES.new(key) ss = obj.decrypt(s) return ss.split(bytes(EOD, 'utf-8'))[0] class AESEncryptedField(models.CharField): + """ A Field that can be used in forms for adding the support + of AES ecnrypted fields """ def save_form_data(self, instance, data): setattr(instance, self.name, binascii.b2a_base64(encrypt(settings.AES_KEY, data))) @@ -41,16 +78,10 @@ class AESEncryptedField(models.CharField): return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode('utf-8') - def from_db_value(self, value, expression, connection, *args): - if value is None: - return value - return decrypt(settings.AES_KEY, - binascii.a2b_base64(value)).decode('utf-8') - def get_prep_value(self, value): if value is None: return value return binascii.b2a_base64(encrypt( - settings.AES_KEY, - value + settings.AES_KEY, + value )) diff --git a/preferences/apps.py b/preferences/apps.py deleted file mode 100644 index 85238099..00000000 --- a/preferences/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class PreferencesConfig(AppConfig): - name = 'preferences' diff --git a/preferences/models.py b/preferences/models.py index c5363fdd..4495f629 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -27,25 +27,31 @@ from __future__ import unicode_literals from django.utils.functional import cached_property from django.db import models -import cotisations.models -import machines.models -from django.db.models.signals import post_save, post_delete +from django.db.models.signals import post_save from django.dispatch import receiver from django.core.cache import cache -from .aes_field import AESEncryptedField +import cotisations.models +import machines.models from re2o.mixins import AclMixin +from .aes_field import AESEncryptedField + class PreferencesModel(models.Model): + """ Base object for the Preferences objects + Defines methods to handle the cache of the settings (they should + not change a lot) """ @classmethod def set_in_cache(cls): + """ Save the preferences in a server-side cache """ instance, _created = cls.objects.get_or_create() cache.set(cls().__class__.__name__.lower(), instance, None) return instance @classmethod def get_cached_value(cls, key): + """ Get the preferences from the server-side cache """ instance = cache.get(cls().__class__.__name__.lower()) if instance is None: instance = cls.set_in_cache() @@ -112,7 +118,7 @@ class OptionalUser(AclMixin, PreferencesModel): @receiver(post_save, sender=OptionalUser) -def optionaluser_post_save(sender, **kwargs): +def optionaluser_post_save(_sender, **kwargs): """Ecriture dans le cache""" user_pref = kwargs['instance'] user_pref.set_in_cache() @@ -147,6 +153,7 @@ class OptionalMachine(AclMixin, PreferencesModel): @cached_property def ipv6(self): + """ Check if the IPv6 option is activated """ return not self.get_cached_value('ipv6_mode') == 'DISABLED' class Meta: @@ -156,7 +163,7 @@ class OptionalMachine(AclMixin, PreferencesModel): @receiver(post_save, sender=OptionalMachine) -def optionalmachine_post_save(sender, **kwargs): +def optionalmachine_post_save(_sender, **kwargs): """Synchronisation ipv6 et ecriture dans le cache""" machine_pref = kwargs['instance'] machine_pref.set_in_cache() @@ -204,7 +211,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): @receiver(post_save, sender=OptionalTopologie) -def optionaltopologie_post_save(sender, **kwargs): +def optionaltopologie_post_save(_sender, **kwargs): """Ecriture dans le cache""" topologie_pref = kwargs['instance'] topologie_pref.set_in_cache() @@ -244,7 +251,7 @@ class GeneralOption(AclMixin, PreferencesModel): @receiver(post_save, sender=GeneralOption) -def generaloption_post_save(sender, **kwargs): +def generaloption_post_save(_sender, **kwargs): """Ecriture dans le cache""" general_pref = kwargs['instance'] general_pref.set_in_cache() @@ -318,7 +325,7 @@ class AssoOption(AclMixin, PreferencesModel): @receiver(post_save, sender=AssoOption) -def assooption_post_save(sender, **kwargs): +def assooption_post_save(_sender, **kwargs): """Ecriture dans le cache""" asso_pref = kwargs['instance'] asso_pref.set_in_cache() diff --git a/preferences/tests.py b/preferences/tests.py index 7ce503c2..8b980c73 100644 --- a/preferences/tests.py +++ b/preferences/tests.py @@ -1,3 +1,29 @@ -from django.test import TestCase +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# Copyright © 2018 Maël Kervella +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +"""preferences.tests +The tests for the Preferences module. +""" + +# from django.test import TestCase # Create your tests here. diff --git a/preferences/urls.py b/preferences/urls.py index d8aba5b9..9b51a432 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -27,8 +27,8 @@ from __future__ import unicode_literals from django.conf.urls import url -from . import views import re2o +from . import views urlpatterns = [ diff --git a/preferences/views.py b/preferences/views.py index aa065d1d..d7971b98 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -31,17 +31,17 @@ topologie, users, service...) from __future__ import unicode_literals from django.urls import reverse -from django.shortcuts import render, redirect +from django.shortcuts import redirect from django.contrib import messages -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.db.models import ProtectedError from django.db import transaction -from reversion.models import Version from reversion import revisions as reversion from re2o.views import form from re2o.acl import can_create, can_edit, can_delete_set, can_view_all + from .forms import ServiceForm, DelServiceForm from .models import Service, OptionalUser, OptionalMachine, AssoOption from .models import MailMessageOption, GeneralOption, OptionalTopologie @@ -136,7 +136,7 @@ def add_service(request): @login_required @can_edit(Service) -def edit_service(request, service_instance, serviceid): +def edit_service(request, service_instance, _serviceid): """Edition des services affichés sur la page d'accueil""" service = ServiceForm(request.POST or None, instance=service_instance) if service.is_valid():