eight-hourr/backend/services/secret_box.py

57 lines
1.4 KiB
Python
Raw Normal View History

2026-07-17 06:55:36 +00:00
from __future__ import annotations
from pathlib import Path
from cryptography.fernet import Fernet, InvalidToken
from paths import DATA_DIR
KEY_FILE = DATA_DIR / ".secret_key"
ENCRYPTED_PREFIX = "enc:"
def _ensure_key() -> bytes:
KEY_FILE.parent.mkdir(parents=True, exist_ok=True)
if KEY_FILE.exists():
raw = KEY_FILE.read_bytes().strip()
if raw:
return raw
key = Fernet.generate_key()
KEY_FILE.write_bytes(key)
try:
KEY_FILE.chmod(0o600)
except OSError:
pass
return key
def _fernet() -> Fernet:
return Fernet(_ensure_key())
def encrypt_secret(plain: str) -> str:
if not plain:
return ""
if plain.startswith(ENCRYPTED_PREFIX):
return plain
token = _fernet().encrypt(plain.encode("utf-8")).decode("ascii")
return f"{ENCRYPTED_PREFIX}{token}"
def decrypt_secret(value: str) -> str:
if not value:
return ""
if not value.startswith(ENCRYPTED_PREFIX):
return value
token = value[len(ENCRYPTED_PREFIX) :].encode("ascii")
try:
return _fernet().decrypt(token).decode("utf-8")
except InvalidToken as exc:
raise ValueError(
"Could not decrypt stored password. Secret key may have changed; re-enter password."
) from exc
def is_encrypted(value: str) -> bool:
return bool(value) and value.startswith(ENCRYPTED_PREFIX)