72 lines
1.8 KiB
Python
72 lines
1.8 KiB
Python
import base64
|
|
import hashlib
|
|
|
|
from cryptography.fernet import Fernet
|
|
from django.conf import settings
|
|
from django.db import models
|
|
|
|
|
|
def _get_fernet() -> Fernet:
|
|
key = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
|
|
return Fernet(base64.urlsafe_b64encode(key))
|
|
|
|
|
|
def encrypt_value(plaintext: str) -> str:
|
|
if not plaintext:
|
|
return ""
|
|
f = _get_fernet()
|
|
return f.encrypt(plaintext.encode()).decode()
|
|
|
|
|
|
def decrypt_value(ciphertext: str) -> str:
|
|
if not ciphertext:
|
|
return ""
|
|
f = _get_fernet()
|
|
return f.decrypt(ciphertext.encode()).decode()
|
|
|
|
|
|
def compute_national_id_hash(value: str) -> str:
|
|
if not value:
|
|
return ""
|
|
salt = settings.SECRET_KEY.encode()
|
|
return hashlib.sha256(salt + value.strip().encode()).hexdigest()
|
|
|
|
|
|
def mask_national_id(value: str) -> str:
|
|
if not value:
|
|
return ""
|
|
value = value.strip()
|
|
if len(value) <= 4:
|
|
return "*" * len(value)
|
|
return "*" * (len(value) - 4) + value[-4:]
|
|
|
|
|
|
class EncryptedCharField(models.CharField):
|
|
def get_prep_value(self, value):
|
|
if not value:
|
|
return value
|
|
return encrypt_value(str(value))
|
|
|
|
def from_db_value(self, value, expression, connection):
|
|
if not value:
|
|
return value
|
|
try:
|
|
return decrypt_value(value)
|
|
except Exception:
|
|
return value
|
|
|
|
def to_python(self, value):
|
|
if not value:
|
|
return value
|
|
if isinstance(value, str):
|
|
try:
|
|
return decrypt_value(value)
|
|
except Exception:
|
|
return value
|
|
return value
|
|
|
|
def deconstruct(self):
|
|
name, path, args, kwargs = super().deconstruct()
|
|
path = "apps.core.encryption.EncryptedCharField"
|
|
return name, path, args, kwargs
|