diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1b463dc00c..b456a20cda 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,11 @@ Change Log Unreleased ---------- + +[4.7.4] +-------- +feat: added fields for holding encrypted data in database + [4.7.3] -------- feat: added management command to re-encrypt enterprise customer reporting configs diff --git a/integrated_channels/moodle/migrations/0028_auto_20230928_1530.py b/integrated_channels/moodle/migrations/0028_auto_20230928_1530.py new file mode 100644 index 0000000000..8e8839840b --- /dev/null +++ b/integrated_channels/moodle/migrations/0028_auto_20230928_1530.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.20 on 2023-09-28 15:30 + +from django.db import migrations +import fernet_fields.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('moodle', '0027_alter_historicalmoodleenterprisecustomerconfiguration_options'), + ] + + operations = [ + migrations.AddField( + model_name='historicalmoodleenterprisecustomerconfiguration', + name='decrypted_password', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's password used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Password'), + ), + migrations.AddField( + model_name='historicalmoodleenterprisecustomerconfiguration', + name='decrypted_token', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's token used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Token'), + ), + migrations.AddField( + model_name='historicalmoodleenterprisecustomerconfiguration', + name='decrypted_username', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's username used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Username'), + ), + migrations.AddField( + model_name='moodleenterprisecustomerconfiguration', + name='decrypted_password', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's password used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Password'), + ), + migrations.AddField( + model_name='moodleenterprisecustomerconfiguration', + name='decrypted_token', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's token used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Token'), + ), + migrations.AddField( + model_name='moodleenterprisecustomerconfiguration', + name='decrypted_username', + field=fernet_fields.fields.EncryptedCharField(blank=True, help_text="The encrypted API user's username used to obtain new tokens. It will be encrypted when stored in the database.", max_length=255, null=True, verbose_name='Encrypted Webservice Username'), + ), + ] diff --git a/integrated_channels/moodle/migrations/0029_auto_20231106_1233.py b/integrated_channels/moodle/migrations/0029_auto_20231106_1233.py new file mode 100644 index 0000000000..ea32466125 --- /dev/null +++ b/integrated_channels/moodle/migrations/0029_auto_20231106_1233.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.20 on 2023-11-06 12:33 + +from django.db import migrations + + +def populate_decrypted_fields(apps, schema_editor): + """ + Populates the encryption fields with the data previously stored in database. + """ + MoodleEnterpriseCustomerConfiguration = apps.get_model('moodle', 'MoodleEnterpriseCustomerConfiguration') + + for moodle_enterprise_configuration in MoodleEnterpriseCustomerConfiguration.objects.all(): + moodle_enterprise_configuration.decrypted_username = moodle_enterprise_configuration.username + moodle_enterprise_configuration.decrypted_password = moodle_enterprise_configuration.password + moodle_enterprise_configuration.decrypted_token = moodle_enterprise_configuration.token + moodle_enterprise_configuration.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('moodle', '0028_auto_20230928_1530'), + ] + + operations = [ + migrations.RunPython(populate_decrypted_fields, reverse_code=migrations.RunPython.noop), + ] diff --git a/integrated_channels/moodle/models.py b/integrated_channels/moodle/models.py index 7e96a6ca8d..5e1a4112c9 100644 --- a/integrated_channels/moodle/models.py +++ b/integrated_channels/moodle/models.py @@ -5,6 +5,7 @@ import json from logging import getLogger +from fernet_fields import EncryptedCharField from simple_history.models import HistoricalRecords from django.db import models @@ -64,6 +65,17 @@ class MoodleEnterpriseCustomerConfiguration(EnterpriseCustomerPluginConfiguratio ) ) + decrypted_username = EncryptedCharField( + max_length=255, + verbose_name="Encrypted Webservice Username", + blank=True, + help_text=_( + "The encrypted API user's username used to obtain new tokens." + " It will be encrypted when stored in the database." + ), + null=True, + ) + password = models.CharField( max_length=255, blank=True, @@ -73,6 +85,17 @@ class MoodleEnterpriseCustomerConfiguration(EnterpriseCustomerPluginConfiguratio ) ) + decrypted_password = EncryptedCharField( + max_length=255, + verbose_name="Encrypted Webservice Password", + blank=True, + help_text=_( + "The encrypted API user's password used to obtain new tokens." + " It will be encrypted when stored in the database." + ), + null=True, + ) + token = models.CharField( max_length=255, blank=True, @@ -82,6 +105,17 @@ class MoodleEnterpriseCustomerConfiguration(EnterpriseCustomerPluginConfiguratio ) ) + decrypted_token = EncryptedCharField( + max_length=255, + verbose_name="Encrypted Webservice Token", + blank=True, + help_text=_( + "The encrypted API user's token used to obtain new tokens." + " It will be encrypted when stored in the database." + ), + null=True, + ) + transmission_chunk_size = models.IntegerField( default=1, help_text=_("The maximum number of data items to transmit to the integrated channel with each request.")