Skip to content

Commit

Permalink
feat: added fields for holding encrypted data in database (ENT 5613)
Browse files Browse the repository at this point in the history
  • Loading branch information
MueezKhan246 committed Oct 3, 2023
1 parent adb7f83 commit 48a4adf
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
58 changes: 58 additions & 0 deletions integrated_channels/moodle/migrations/0028_auto_20230928_1530.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 3.2.20 on 2023-09-28 15:30

from django.db import migrations
import fernet_fields.fields


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', '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.", 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.", 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.", 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.", 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.", 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.", max_length=255, null=True, verbose_name='Encrypted Webservice Username'),
),
migrations.RunPython(populate_decrypted_fields),
]
98 changes: 98 additions & 0 deletions integrated_channels/moodle/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import json
from logging import getLogger

from fernet_fields import EncryptedCharField
from simple_history.models import HistoricalRecords

from django.db import models
from django.utils.encoding import force_bytes, force_str
from django.utils.translation import gettext_lazy as _

from integrated_channels.integrated_channel.models import (
Expand Down Expand Up @@ -64,6 +66,38 @@ 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."),
null=True,
)

@property
def encrypted_username(self):
"""
Return encrypted username as a string.
The data is encrypted in the DB at rest, but is unencrypted in the app when retrieved through the
decrypted_username field. This method will encrypt the username again before sending.
"""
if self.decrypted_username:
return force_str(
self._meta.get_field('decrypted_username').fernet.encrypt(
force_bytes(self.decrypted_username)
)
)
return self.decrypted_username

@encrypted_username.setter
def encrypted_username(self, value):
"""
Set the encrypted username.
"""
self.decrypted_username = value

password = models.CharField(
max_length=255,
blank=True,
Expand All @@ -73,6 +107,38 @@ 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."),
null=True,
)

@property
def encrypted_password(self):
"""
Return encrypted password as a string.
The data is encrypted in the DB at rest, but is unencrypted in the app when retrieved through the
decrypted_password field. This method will encrypt the password again before sending.
"""
if self.decrypted_password:
return force_str(
self._meta.get_field('decrypted_password').fernet.encrypt(
force_bytes(self.decrypted_password)
)
)
return self.decrypted_password

@encrypted_password.setter
def encrypted_password(self, value):
"""
Set the encrypted password.
"""
self.decrypted_password = value

token = models.CharField(
max_length=255,
blank=True,
Expand All @@ -82,6 +148,38 @@ 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."),
null=True,
)

@property
def encrypted_token(self):
"""
Return encrypted token as a string.
The data is encrypted in the DB at rest, but is unencrypted in the app when retrieved through the
decrypted_token field. This method will encrypt the token again before sending.
"""
if self.decrypted_token:
return force_str(
self._meta.get_field('decrypted_token').fernet.encrypt(
force_bytes(self.decrypted_token)
)
)
return self.decrypted_token

@encrypted_token.setter
def encrypted_token(self, value):
"""
Set the encrypted token.
"""
self.decrypted_token = value

transmission_chunk_size = models.IntegerField(
default=1,
help_text=_("The maximum number of data items to transmit to the integrated channel with each request.")
Expand Down

0 comments on commit 48a4adf

Please sign in to comment.