feat(backend): pose les primitives de sécurité
Couche pure, sans FastAPI ni session : rôles ordonnés, `Principal`, encodage et décodage des jetons d'accès, empreinte des jetons de rafraîchissement, et hachage Argon2id poussé dans un fil borné. Aucun de ces modules ne lit `get_settings()`, mis en cache par `lru_cache` et donc contaminé entre tests : les paramètres arrivent par `TokenPolicy` et par `build_hasher()`. Argon2id est calibré à m=19456 KiB, t=2, p=1, soit 17 ms mesurés sur un poste de développement.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
from enum import StrEnum
|
||||
from typing import Final
|
||||
|
||||
|
||||
class Role(StrEnum):
|
||||
# Contrainte : ces valeurs voyagent en base, en JSON et dans les jetons. Elles restent
|
||||
# en ASCII, contrairement au libellé « opérateur » affiché à l'utilisateur.
|
||||
LECTEUR = "lecteur"
|
||||
OPERATEUR = "operateur"
|
||||
ADMIN = "admin"
|
||||
|
||||
|
||||
class AccountKind(StrEnum):
|
||||
HUMAIN = "human"
|
||||
SERVICE = "service"
|
||||
|
||||
|
||||
ROLE_RANK: Final[dict[Role, int]] = {
|
||||
Role.LECTEUR: 0,
|
||||
Role.OPERATEUR: 1,
|
||||
Role.ADMIN: 2,
|
||||
}
|
||||
|
||||
|
||||
def has_at_least(actual: Role, required: Role) -> bool:
|
||||
return ROLE_RANK[actual] >= ROLE_RANK[required]
|
||||
Reference in New Issue
Block a user