Files
meet/src/backend/core/fields.py
T
briquet 833ba48d65 ⬆️(backend) upgrade pylint to 4.1.3
pylint was pinned below 4.0 because pylint-django used to require it.
pylint-django 2.8.0 accepts pylint 4.

pylint 3.x kept too-many-lines pragma line numbers across modules: a C0302
disable in one file could make the check report on the wrong line
in another and fail depending on how files were spread across jobs.
pylint 4.1 resets them per module.

cf https://github.com/pylint-dev/pylint/pull/11191
2026-10-12 18:57:18 +02:00

54 lines
1.6 KiB
Python

"""
Core application fields
"""
from logging import getLogger
from django.contrib.auth.hashers import identify_hasher, make_password
from django.db import models
from .hashers import CLIENT_SECRET_HASH_PATTERN
logger = getLogger(__name__)
class SecretField(models.CharField):
"""CharField that automatically hashes secrets before saving.
Use for API keys, client secrets, or tokens that should never be stored
in plain text. Already-hashed values are preserved to prevent double-hashing.
Inspired by: https://github.com/django-oauth-toolkit/django-oauth-toolkit
"""
def pre_save(self, model_instance, add):
"""Hash the secret if not already hashed, otherwise preserve it."""
secret = getattr(model_instance, self.attname)
if CLIENT_SECRET_HASH_PATTERN.fullmatch(secret):
logger.debug(
"%s: %s is already hashed with sha256.",
model_instance,
self.attname,
)
return secret
try:
hasher = identify_hasher(secret)
logger.debug(
"%s: %s is already hashed with %s.",
model_instance,
self.attname,
hasher,
)
except ValueError:
logger.debug(
"%s: %s is not hashed; hashing it now.", model_instance, self.attname
)
hashed_secret = make_password(secret)
setattr(model_instance, self.attname, hashed_secret)
return hashed_secret
return super().pre_save(model_instance, add) # pylint: disable=no-member