Monday, 30 December 2019

Django Admin encrypt values of certain fields on changed(or save) with save_model()

I currently having a custom User model which some of the fields are supposed to be encrypted (data side) but on Django Admin they need to be decrypted to show the actual data so i have encrypt_string() and decrypt_string() function to handle it.

My user model:

class User(AbstractUser):
    uid = models.CharField(
      "uid", max_length=255, null=True, blank=True)
    nickname = models.CharField(
        "Nickname", max_length=255, null=True, blank=True)

    eth_address = models.CharField(
        "Eth address", max_length=255, null=True, blank=True)
    eth_private_key = models.CharField(
        "Eth private key", max_length=255, null=True, blank=True)
    evt_address = models.CharField(
        "Evt address", max_length=255, null=True, blank=True)
    evt_private_key = models.CharField(
        "Evt private key", max_length=255, null=True, blank=True)

eth_address, eth_private_key, evt_address and evt_private_key need to be encrypted when doing any kind of saving or edit

Currently when my server request from an api it will create a default user(handle on custom authentication_class of django-rest-framework):

existed_user_check = User.objects.filter(uid=uid).exists()

    if not existed_user_check:
        random_password = ''.join(["{}".format(randint(0, 9)) for num in range(0, 6)])
        eth_address, eth_private_key = generate_eth()
        evt_address, evt_private_key = generate_evt()
        new_user = User(
            username=uid, 
            uid=uid, 
            eth_address=encrypt_string(eth_address), 
            eth_private_key=encrypt_string(eth_private_key), 
            evt_address=encrypt_string(evt_address), 
            evt_private_key=encrypt_string(evt_private_key)
        )
        new_user.set_password(random_password)
        new_user.save()

And on my Django Admin i wrote the following in the admin.py to handle decrypt(when showing the data on change view) and encrypt(when doing any saving or edit of those 4 fields):

user_profile_encrypt_fields = [
    'eth_address',
    'eth_private_key',
    'evt_address',
    'evt_private_key'
]
class UserAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(UserAdminForm, self).__init__(*args, **kwargs)
        for field in user_profile_encrypt_fields:
            if getattr(self.instance, field) is not None:
                try:
                    self.initial[field] = decrypt_string(getattr(self.instance, field))
                except Exception as e:
                    pass


class UserAdminCustom(admin.ModelAdmin):
    # UserAdminForm handle decrypt data
    form = UserAdminForm
    exclude = ('password', 'last_login', 'is_superuser', 'is_staff', 'groups',
               'user_permissions', 'username', 'first_name', 'last_name', 'is_active', 'date_joined')

    def get_queryset(self, request):
        qs = super(UserAdminCustom, self).get_queryset(request)
        return qs.filter(is_staff=False)

    def get_readonly_fields(self, request, obj=None):
        return ('id', 'created', 'modified')

    # save_model() handle encrypt data on saving
    def save_model(self, request, obj, form, change):
        for field in form.changed_data:
            if form.cleaned_data.get(field) is not None:
                if field in user_profile_encrypt_fields:
                    encrypted_value = encrypt_string(form.cleaned_data.get(field))
                    setattr(obj, field, encrypted_value)
        obj.save()


admin.site.register(User, UserAdminCustom)

Custom UserAdminForm for me to decrypt the data so the admin can see what it's when they doing the editing or checking. The decrypted data are able to be showed on the change view correctly

save_model() will handle the encrypting of data when admin edit a fields on Django Admin change view.

My current problem:

NOTES:

The data in these fields existed so i'm only talking about the editing object part on django admin.

When ever i tried to edit any of the field and save it(should be encrypted) that field got encrypted and saved, but the field below it (actual encrypted data of it) now changed to it's actual data(not encrypted)

After i edited evt_address on the change view and save

decrypted data when use form = UserAdminForm

enter image description here

comment out # form = UserAdminForm on the UserAdminCustom so it show the actual data

enter image description here

I printed out the getattr(self.instance, field) to see the encrypted data on loading the django admin change view and got the following 4 encrypted field:

web_1         | eth_address : gAAAAABeAcoI08bH2fQqJboZFxg6xn5RCxdRopllS6fDeyRmsC3qzsTXo88NVYOb58eeX5IXQpxqcGhbLr8wRRoWSKQsX5vLbPPhmWqUiqf0XYQvdWUhhgYxxMwwqgEOwU2OtJfkZ0p6
web_1         | eth_private_key : gAAAAABeAcoIp1V9sKNnL-dO-fWH1W1oM7hbqky44aRLchmTtvckaaZdaKuXo1xIIozx3xl40Y2Ct3YAyCOfkJJranKgTNDcVhndYdu5-awOuYpPCJKkSSia7IP_gWjLE91Gh8vsGnkn1iEkrLaho2ff0vVHS1QgGaJxji5m7cwCk0tqSp2AIeA=
web_1         | evt_address : gAAAAABeAcoIM3rywSgAPL611WUoWLJ9mqIgUHhZn8KDQd9hi9xHzgRri0EkoS_yBvwQyzdH72RWJRsDCs38oF9P8HHW_wFDWQ==
web_1         | evt_private_key : 1814067

so my evt_private_key data got changed to 1814067 after i edited evt_address value and save

Why is this happening, i'm so confused on what causing this.

Hope someone can help me



from Django Admin encrypt values of certain fields on changed(or save) with save_model()

No comments:

Post a Comment