Comments (4)
When I submit a form in Django Admin, it calls default "clean()" function which is:
def clean(self, value, model_instance):
"""
Convert the value's type and run validation. Validation errors
from to_python() and validate() are propagated. Return the correct
value if no error is raised.
"""
value = self.to_python(value)
self.validate(value, model_instance)
self.run_validators(value)
return value
The problem is in self.to_python(value)
. Variable value
is the input from form (can be any text by app user).
This call self.to_python(value)
is going to encrypted_fields/fields.py
:
def to_python(self, value):
if value is None or not isinstance(value, str):
return value
value = self.f.decrypt(bytes(value, 'utf-8')).decode('utf-8')
return super(EncryptedFieldMixin, self).to_python(value)
raising error in value = self.f.decrypt(bytes(value, 'utf-8')).decode('utf-8')
.
So, any Django Admin form input (like "Hello World!") is going to be decrypted in self.f.decrypt(bytes('Hello World!', 'utf-8'))
. That's the error cause, because decrypt is expecting an encrypted string.
The encrypted_fields to_python(self, value)
may be overriding Django's (from django.db.models.fields) to_python(self, value)
? Any tip on this?
Thanks in advance.
from django-fernet-encrypted-fields.
What format is your token? The InvalidToken is not being raise by this package but it being raised by the main pyca cryptography package -
https://github.com/pyca/cryptography/blob/main/src/cryptography/fernet.py
If you look at that package the line raising the validation is this
if not data or data[0] != 0x80:
raise InvalidToken
from django-fernet-encrypted-fields.
Here's how I've added a work around for my project
- Create a custom Admin class for the model you are using and set that class against the form property of the ModelAdmin or inline form
- With the custom form you've created import the EncryptedFieldMixin and overload the _get_validation_exclusions method with the following:
def _get_validation_exclusions(self):
"""Overload this method to add the encrypted fields to the list of exclusions used by full_clean"""
exclude = super()._get_validation_exclusions()
for field in self.fields:
if isinstance(getattr(self._meta.model, field).field, EncryptedFieldMixin):
exclude.append(field)
return exclude
This will add any Encrypted fields on the model that you are using into the exclusion list created by the _post_clean method which then calls the full_clean method on the instance.
You can still add custom validation to the clean_* methods on the form to validate and raise any errors.
I need to check but it may be possible to move this into the EncryptedFieldMixin class against it's full_clean method as well but I have not tested that far down yet.
Here's an example where my model UserProfile has two encrypted fields
admin.py
class UserProfileInline(admin.StackedInline):
model = UserProfile
form = UserProfileAdminForm
forms.py
from encrypted_fields.fields import EncryptedFieldMixin
class UserProfileAdminForm(ModelForm):
class Meta:
model = UserProfile
def _get_validation_exclusions(self):
"""Overload this method to add the encrypted fields to the list of exclusions used by full_clean"""
exclude = super()._get_validation_exclusions()
for field in self.fields:
if isinstance(getattr(self._meta.model, field).field, EncryptedFieldMixin):
exclude.append(field)
return exclude
from django-fernet-encrypted-fields.
Okay I tested the model level and this can be fixed by overloading the clean method at the base model field level by simply running the actions of django.db.models.fields.init.clean without calling the to_python
def clean(self, value, model_instance):
"""
Convert the value's type and run validation. Validation errors
from to_python() and validate() are propagated. Return the correct
value if no error is raised.
"""
self.validate(value, model_instance)
self.run_validators(value)
return value
However a better method, IMO, would be to use a temporary instance property which we create within the clean method, then call the super, then remove it from the instance. This means the to_python method can be updated to check for that property and, if it exists, can skip decryption. It's more code but means it's less likely to break with future changes to Django's field's clean method as we know it will run as it's suppose to.
def to_python(self, value):
if value is None or not isinstance(value, str) or hasattr(self, '_already_decrypted'):
return value
value = self.f.decrypt(bytes(value, 'utf-8')).decode('utf-8')
return super(EncryptedFieldMixin, self).to_python(value)
def clean(self, value, model_instance):
"""
Convert the value's type and run validation. Validation errors
from to_python() and validate() are propagated. Return the correct
value if no error is raised.
"""
self._already_decrypted = True
ret = super().clean(value, model_instance)
del self._already_decrypted
return ret
I'll fork and create a new PR based on the latter
from django-fernet-encrypted-fields.
Related Issues (9)
- I got KeyError: TextField when I tried using EncryptedIntegerField HOT 3
- Issues with lookups against encrypted fields HOT 2
- Updating Django's SECRET_KEY makes encrypted fields inaccessible HOT 7
- Adding typings to codebase HOT 5
- Implement Jazzband guidelines for django-fernet-encrypted-fields HOT 2
- Feature Request: Add support for rotating the salt HOT 1
- Reasons for not leaving SECRET_KEY used as default HOT 1
- Joining Jazzband HOT 12
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from django-fernet-encrypted-fields.