novela/containers/novela/security.py

44 lines
1.0 KiB
Python

import base64
import hashlib
import os
from cryptography.fernet import Fernet, InvalidToken
_PREFIX = "enc$"
def _master_secret() -> str:
return (
os.environ.get("NOVELA_MASTER_KEY")
or os.environ.get("POSTGRES_PASSWORD")
or "novela-default-key-change-me"
)
def _fernet() -> Fernet:
digest = hashlib.sha256(_master_secret().encode("utf-8")).digest()
key = base64.urlsafe_b64encode(digest)
return Fernet(key)
def encrypt_value(value: str | None) -> str:
raw = value or ""
token = _fernet().encrypt(raw.encode("utf-8")).decode("utf-8")
return _PREFIX + token
def is_encrypted_value(value: str | None) -> bool:
return bool(value) and str(value).startswith(_PREFIX)
def decrypt_value(value: str | None) -> str:
if not value:
return ""
if not value.startswith(_PREFIX):
return value
token = value[len(_PREFIX) :]
try:
return _fernet().decrypt(token.encode("utf-8")).decode("utf-8")
except InvalidToken:
return ""