feat: Semaine 8
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
class SecuVaultError(Exception):
|
||||
"""Base exception for all SecuVault domain errors."""
|
||||
|
||||
class AuthenticationError(SecuVaultError):
|
||||
"""Bad credentials or inactive account."""
|
||||
|
||||
class AccessDeniedError(SecuVaultError):
|
||||
"""User is not authorised to access the requested resource."""
|
||||
|
||||
class SecretNotFoundError(SecuVaultError):
|
||||
"""Requested secret does not exist."""
|
||||
|
||||
class TeamNotFoundError(SecuVaultError):
|
||||
"""Requested team does not exist."""
|
||||
|
||||
class ConflictError(SecuVaultError):
|
||||
"""Optimistic-locking detected a concurrent modification conflict."""
|
||||
@@ -0,0 +1,11 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Secret:
|
||||
id: int
|
||||
name: str
|
||||
encrypted_value: str
|
||||
team_id: int
|
||||
version: int
|
||||
created_at: str
|
||||
updated_at: str
|
||||
@@ -0,0 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Team:
|
||||
id: int
|
||||
name: str
|
||||
description: str | None = None
|
||||
@@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
id: int
|
||||
username: str
|
||||
teams_id: list[int]
|
||||
password_hash: str
|
||||
is_active: bool = True
|
||||
@@ -0,0 +1,68 @@
|
||||
from domain.exceptions import (
|
||||
AccessDeniedError,
|
||||
AuthenticationError,
|
||||
ConflictError,
|
||||
SecretNotFoundError,
|
||||
)
|
||||
from domain.models.secrets import Secret
|
||||
from domain.models.users import User
|
||||
|
||||
def authenticate_user(username: str, password: str, user_repository, crypto) -> User:
|
||||
user = user_repository.find_by_username(username)
|
||||
if user is None or not user.is_active:
|
||||
raise AuthenticationError("Identifiants incorrects.")
|
||||
if not crypto.verify_password(password, user.password_hash):
|
||||
raise AuthenticationError("Identifiants incorrects.")
|
||||
return user
|
||||
|
||||
def check_team_membership(user: User, team_id: int) -> None:
|
||||
if team_id not in user.teams_id:
|
||||
raise AccessDeniedError("Vous n'\u00eates pas membre de cette \u00e9quipe.")
|
||||
|
||||
def list_secrets_for_team(user: User, team_id: int, secret_repository) -> list[Secret]:
|
||||
check_team_membership(user, team_id)
|
||||
return secret_repository.find_by_team_id(team_id)
|
||||
|
||||
def reveal_secret(user: User, secret_id: int, secret_repository, crypto) -> str:
|
||||
secret = secret_repository.find_by_id(secret_id)
|
||||
if secret is None:
|
||||
raise SecretNotFoundError("Secret introuvable.")
|
||||
check_team_membership(user, secret.team_id)
|
||||
return crypto.decrypt_secret(secret.encrypted_value)
|
||||
|
||||
def create_secret(
|
||||
user: User,
|
||||
team_id: int,
|
||||
name: str,
|
||||
value: str,
|
||||
secret_repository,
|
||||
crypto,
|
||||
) -> Secret:
|
||||
check_team_membership(user, team_id)
|
||||
encrypted_value = crypto.encrypt_secret(value)
|
||||
return secret_repository.create(name=name, encrypted_value=encrypted_value, team_id=team_id)
|
||||
|
||||
def rotate_secret(
|
||||
user: User,
|
||||
secret_id: int,
|
||||
new_value: str,
|
||||
expected_version: int,
|
||||
secret_repository,
|
||||
crypto,
|
||||
) -> Secret:
|
||||
secret = secret_repository.find_by_id(secret_id)
|
||||
if secret is None:
|
||||
raise SecretNotFoundError("Secret introuvable.")
|
||||
check_team_membership(user, secret.team_id)
|
||||
if secret.version != expected_version:
|
||||
raise ConflictError(
|
||||
"Ce secret a été modifié par quelqu'un d'autre depuis que vous avez ouvert "
|
||||
"le formulaire. Veuillez recharger la page et réessayer."
|
||||
)
|
||||
encrypted_value = crypto.encrypt_secret(new_value)
|
||||
updated = secret_repository.update(secret_id, encrypted_value, expected_version)
|
||||
if updated is None:
|
||||
raise ConflictError(
|
||||
"Conflit de modification détecté. Veuillez recharger et réessayer."
|
||||
)
|
||||
return updated
|
||||
Reference in New Issue
Block a user