Reject invalid SOCIAL_TOKEN_ENCRYPTION_KEY instead of 500ing.
Placeholder Fernet values like replace-with-fernet-key now raise a clear SocialCryptoError in the portal, and prod env examples no longer ship a fake key.
This commit is contained in:
+48
-8
@@ -1,17 +1,55 @@
|
||||
"""Token encryption helpers for SocialAccount."""
|
||||
"""Token encryption helpers for SocialAccount / SocialAppCredentials."""
|
||||
|
||||
from cryptography.fernet import Fernet, InvalidToken
|
||||
from django.conf import settings
|
||||
|
||||
# Copied from .env.prod.example / deploy templates — not valid Fernet material.
|
||||
_PLACEHOLDER_KEYS = frozenset(
|
||||
{
|
||||
"replace-with-fernet-key",
|
||||
"changeme",
|
||||
"change-me",
|
||||
"todo",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class SocialCryptoError(ValueError):
|
||||
"""Raised when SOCIAL_TOKEN_ENCRYPTION_KEY is missing or not a Fernet key."""
|
||||
|
||||
|
||||
def _normalize_key(raw: str | bytes | None) -> bytes | None:
|
||||
if raw is None:
|
||||
return None
|
||||
if isinstance(raw, bytes):
|
||||
text = raw.decode("utf-8", errors="ignore").strip()
|
||||
else:
|
||||
text = str(raw).strip()
|
||||
if not text or text.lower() in _PLACEHOLDER_KEYS:
|
||||
return None
|
||||
return text.encode()
|
||||
|
||||
|
||||
def _fernet() -> Fernet:
|
||||
key = settings.SOCIAL_TOKEN_ENCRYPTION_KEY
|
||||
if not key:
|
||||
# Dev-only fallback — generate is not stable across restarts; set the env var.
|
||||
key = Fernet.generate_key().decode()
|
||||
if isinstance(key, str):
|
||||
key = key.encode()
|
||||
return Fernet(key)
|
||||
key = _normalize_key(settings.SOCIAL_TOKEN_ENCRYPTION_KEY)
|
||||
if key is None:
|
||||
if settings.DEBUG:
|
||||
# Dev-only unstable fallback — set SOCIAL_TOKEN_ENCRYPTION_KEY for real use.
|
||||
return Fernet(Fernet.generate_key())
|
||||
raise SocialCryptoError(
|
||||
"SOCIAL_TOKEN_ENCRYPTION_KEY is not set. Generate one with: "
|
||||
'python -c "from cryptography.fernet import Fernet; '
|
||||
'print(Fernet.generate_key().decode())" '
|
||||
"and add it to the beta/prod app env, then redeploy/restart."
|
||||
)
|
||||
try:
|
||||
return Fernet(key)
|
||||
except (ValueError, TypeError) as exc:
|
||||
raise SocialCryptoError(
|
||||
"SOCIAL_TOKEN_ENCRYPTION_KEY is invalid (must be 32 url-safe "
|
||||
"base64-encoded bytes from Fernet.generate_key()). "
|
||||
"Replace the placeholder in the beta/prod env and restart."
|
||||
) from exc
|
||||
|
||||
|
||||
def encrypt_tokens(plaintext: str) -> str:
|
||||
@@ -25,3 +63,5 @@ def decrypt_tokens(ciphertext: str) -> str:
|
||||
return _fernet().decrypt(ciphertext.encode()).decode()
|
||||
except InvalidToken as exc:
|
||||
raise ValueError("Unable to decrypt social tokens") from exc
|
||||
except SocialCryptoError:
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user