Files
IT_Ticket_System/app/services/crypto_service.py
T
2026-07-02 16:11:39 -04:00

46 lines
1.5 KiB
Python

"""
Symmetric encryption for secrets stored in SystemSetting (currently just
the IMAP mailbox password used by email ingestion).
The Fernet key is derived from SECRET_KEY rather than a separately managed
key, so no extra key-rotation story is needed for a single-tenant on-prem
app — rotating SECRET_KEY (which already invalidates sessions) also
invalidates encrypted secrets, which is an acceptable trade-off here.
"""
import base64
import hashlib
from cryptography.fernet import Fernet, InvalidToken
from flask import current_app
def _fernet() -> Fernet:
secret = current_app.config['SECRET_KEY'].encode()
key = base64.urlsafe_b64encode(hashlib.sha256(secret).digest())
return Fernet(key)
def encrypt_secret(plain: str) -> str:
"""Encrypt a secret for storage. Empty input passes through unchanged."""
if not plain:
return ''
return _fernet().encrypt(plain.encode()).decode()
def decrypt_secret(stored: str) -> str:
"""Decrypt a secret previously written by encrypt_secret().
Falls back to returning the value unchanged if it isn't a valid Fernet
token. This covers values saved before encryption was introduced, so
existing configurations (e.g. email ingestion set up before this change)
keep working without a manual data migration — the value is simply
re-encrypted the next time it's saved through the settings form.
"""
if not stored:
return ''
try:
return _fernet().decrypt(stored.encode()).decode()
except (InvalidToken, ValueError):
return stored