Modules: Dashboard, Serveurs, Campagnes, Planning, Specifiques, Settings, Users Stack: FastAPI + Jinja2 + HTMX + Alpine.js + TailwindCSS + PostgreSQL Features: Qualys sync, prereqs auto, planning annuel, server specifics, role-based access Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
"""Service secrets — chiffrement Fernet pour credentials en base"""
|
|
import os
|
|
import base64
|
|
from cryptography.fernet import Fernet
|
|
from sqlalchemy import text
|
|
from ..config import SECRET_KEY
|
|
|
|
# Derive une cle Fernet 32 bytes depuis SECRET_KEY
|
|
_raw = SECRET_KEY.encode()[:32].ljust(32, b'\0')
|
|
_fernet_key = base64.urlsafe_b64encode(_raw)
|
|
_fernet = Fernet(_fernet_key)
|
|
|
|
|
|
def encrypt(value: str) -> str:
|
|
return _fernet.encrypt(value.encode()).decode()
|
|
|
|
|
|
def decrypt(value: str) -> str:
|
|
return _fernet.decrypt(value.encode()).decode()
|
|
|
|
|
|
def get_secret(db, key: str) -> str | None:
|
|
"""Recupere et dechiffre un secret depuis app_secrets"""
|
|
row = db.execute(text("SELECT value FROM app_secrets WHERE key = :k"), {"k": key}).fetchone()
|
|
if not row:
|
|
return None
|
|
try:
|
|
return decrypt(row.value)
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def set_secret(db, key: str, value: str, description: str = ""):
|
|
"""Chiffre et stocke un secret dans app_secrets"""
|
|
enc = encrypt(value)
|
|
db.execute(text("""
|
|
INSERT INTO app_secrets (key, value, description, updated_at)
|
|
VALUES (:k, :v, :d, now())
|
|
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value,
|
|
description = EXCLUDED.description, updated_at = now()
|
|
"""), {"k": key, "v": enc, "d": description})
|
|
db.commit()
|
|
|
|
|
|
def list_secrets(db):
|
|
"""Liste les cles (sans valeurs) des secrets"""
|
|
rows = db.execute(text(
|
|
"SELECT key, description, updated_at FROM app_secrets ORDER BY key"
|
|
)).fetchall()
|
|
return rows
|
|
|
|
|
|
def init_secrets_from_config(db):
|
|
"""Initialise les secrets depuis config si pas encore en base"""
|
|
from ..config import QUALYS_URL, QUALYS_USER, QUALYS_PASS
|
|
defaults = {
|
|
"qualys_url": (QUALYS_URL, "URL API Qualys"),
|
|
"qualys_user": (QUALYS_USER, "Utilisateur Qualys"),
|
|
"qualys_pass": (QUALYS_PASS, "Mot de passe Qualys"),
|
|
"qualys_proxy": ("http://proxy.sanef.fr:8080", "Proxy Qualys"),
|
|
}
|
|
for key, (val, desc) in defaults.items():
|
|
if val and not get_secret(db, key):
|
|
set_secret(db, key, val, desc)
|