secrets: afficher/masquer + copier la valeur, revelation gestionnaire auditee (og/coffres.py)
This commit is contained in:
@@ -12,6 +12,14 @@ Règles d'or, appliquées côté serveur à chaque requête :
|
|||||||
- Seul ``POST /api/coffres/distribuer`` rend une valeur, et uniquement à
|
- Seul ``POST /api/coffres/distribuer`` rend une valeur, et uniquement à
|
||||||
un consommateur authentifié par jeton (hash + jti, jamais la session
|
un consommateur authentifié par jeton (hash + jti, jamais la session
|
||||||
utilisateur), avec un octroi actif et un contexte obligatoire.
|
utilisateur), avec un octroi actif et un contexte obligatoire.
|
||||||
|
- Seule exception, voulue : ``POST /api/coffres/{slug}/secrets/{nom}/reveler``
|
||||||
|
rend la valeur au gestionnaire du coffre authentifié par sa session
|
||||||
|
(propriétaire, ou admin sur coffre d'instance — jamais un simple
|
||||||
|
lecteur par octroi utilisateur), pour l'affichage et la copie manuelle
|
||||||
|
dans le panneau détail. Chaque révélation est auditée
|
||||||
|
(``revelation_manuelle``) et met à jour la dernière utilisation ; la
|
||||||
|
valeur n'est jamais journalisée et le frontend l'efface dès qu'elle
|
||||||
|
est masquée ou que le détail change.
|
||||||
- Autorisations (spec §6) : le propriétaire seul sur son coffre
|
- Autorisations (spec §6) : le propriétaire seul sur son coffre
|
||||||
personnel ; l'admin gère les coffres d'instance, les consommateurs et
|
personnel ; l'admin gère les coffres d'instance, les consommateurs et
|
||||||
la KEK, jamais le coffre personnel d'autrui ; l'ACL « * » des vaults
|
la KEK, jamais le coffre personnel d'autrui ; l'ACL « * » des vaults
|
||||||
@@ -622,6 +630,50 @@ async def api_rotate_secret(
|
|||||||
return _metadata_secret(coffre, secret)
|
return _metadata_secret(coffre, secret)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/api/coffres/{slug}/secrets/{nom}/reveler")
|
||||||
|
async def api_reveler_secret(
|
||||||
|
slug: str, nom: str, current_user=Depends(require_auth)
|
||||||
|
):
|
||||||
|
"""Révélation manuelle pour le panneau détail (afficher / copier).
|
||||||
|
|
||||||
|
Session utilisateur + gestion du coffre exigées : un lecteur par
|
||||||
|
octroi utilisateur voit les métadonnées mais ne révèle jamais la
|
||||||
|
valeur. Chaque appel est audité et touche la dernière utilisation.
|
||||||
|
"""
|
||||||
|
_exiger_actives()
|
||||||
|
coffre = _coffre_or_404(slug)
|
||||||
|
_exiger_gerer(current_user, coffre)
|
||||||
|
secret = _secret_or_404(coffre, nom)
|
||||||
|
try:
|
||||||
|
valeur = distribuer_valeur(coffre, secret)
|
||||||
|
except SecretExpireError:
|
||||||
|
_audit(_username(current_user), "revelation_refusee",
|
||||||
|
coffre=coffre["slug"],
|
||||||
|
secret_ref=f"coffre:{coffre['slug']}/{secret['nom']}",
|
||||||
|
resultat="secret_expire")
|
||||||
|
raise HTTPException(status_code=410, detail="secret_expire") from None
|
||||||
|
except KEKAbsenteError:
|
||||||
|
_audit(_username(current_user), "revelation_refusee",
|
||||||
|
coffre=coffre["slug"],
|
||||||
|
secret_ref=f"coffre:{coffre['slug']}/{secret['nom']}",
|
||||||
|
resultat="kek_absente")
|
||||||
|
raise HTTPException(status_code=503, detail="kek_absente") from None
|
||||||
|
except CryptoIndisponibleError:
|
||||||
|
_audit(_username(current_user), "revelation_refusee",
|
||||||
|
coffre=coffre["slug"],
|
||||||
|
secret_ref=f"coffre:{coffre['slug']}/{secret['nom']}",
|
||||||
|
resultat="crypto_indisponible")
|
||||||
|
raise HTTPException(status_code=503,
|
||||||
|
detail="crypto_indisponible") from None
|
||||||
|
toucher_utilisation(secret["id"])
|
||||||
|
_audit(_username(current_user), "revelation_manuelle",
|
||||||
|
coffre=coffre["slug"],
|
||||||
|
secret_ref=f"coffre:{coffre['slug']}/{secret['nom']}",
|
||||||
|
resultat="ok")
|
||||||
|
return {"reference": f"coffre:{coffre['slug']}/{secret['nom']}",
|
||||||
|
"valeur": valeur, "version": secret["version_courante"]}
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/api/coffres/{slug}/secrets/{nom}")
|
@router.delete("/api/coffres/{slug}/secrets/{nom}")
|
||||||
async def api_delete_secret(
|
async def api_delete_secret(
|
||||||
slug: str, nom: str, current_user=Depends(require_auth)
|
slug: str, nom: str, current_user=Depends(require_auth)
|
||||||
|
|||||||
Reference in New Issue
Block a user