Services et API interne — Référence
Ce document liste tous les services publics de gitrust (rustwarden-core + gitrust-core), leurs signatures Rust, les erreurs possibles, et quand les utiliser.
Architecture générale
Handler Axum → Service (logique métier) → SeaORM (base de données)
Conventions communes :
- Les services sont des structs sans état avec des méthodes associées
async fn. - Premier paramètre toujours
db: &DatabaseConnection. - Type de retour toujours
Result<T, AppError>(rustwarden-core) ouResult<T, GitrustError>(gitrust-core). - Aucun
unwrap()/expect()en production. - Aucun SQL brut — tout passe par SeaORM.
Services rustwarden-core (framework)
Importés via use rustwarden_core::prelude::* pour les exports du prélude, ou via leur chemin complet.
AuthService
Module : rustwarden_core::services::auth_service
| Méthode | Signature | Description |
|---|---|---|
verify_credentials | (db, identifier: &str, password: &str) → Result<user::Model> | Vérifie les identifiants. identifier accepte un username ou un email. Utilise un dummy hash si l'utilisateur n'existe pas (protection timing attack SEC-C1). |
authenticate_user | (db, identifier: &str, password: &str) → Result<user::Model> | Authentification de haut niveau. Appelle verify_credentials et logue must_change_password. |
UserService
Module : rustwarden_core::services::user_service — Export : prélude
| Méthode | Signature | Description |
|---|---|---|
create_user | (db, username, email, password_hash, must_change_password) → Result<user::Model> | Crée un utilisateur. Le mot de passe doit être pré-haché via PasswordService::hash_password. |
get_user_by_id | (db, user_id: Uuid) → Result<Option<user::Model>> | Recherche par ID. |
get_user_by_username | (db, username: &str) → Result<Option<user::Model>> | Recherche par nom d'utilisateur. |
get_user_by_email | (db, email: &str) → Result<Option<user::Model>> | Recherche par email. |
list_all_users | (db) → Result<Vec<user::Model>> | Liste tous les utilisateurs. |
get_user_roles | (db, user_id: Uuid) → Result<Vec<String>> | Retourne les noms des rôles. |
assign_role_to_user | (db, user_id, role_id) → Result<user_role::Model> | Assigne un rôle. |
update_profile | (db, user_id, username: Option<String>, email: Option<String>) → Result<user::Model> | Met à jour le profil. Valide l'unicité. |
change_password | (db, user_id, old_password, new_password, current_token_id) → Result<(Uuid, String)> | Initie un changement de mot de passe (demande pendante). Retourne (request_id, plain_token). |
PasswordService
Module : rustwarden_core::services::password_service
| Méthode | Signature | Description |
|---|---|---|
hash_password | async (password: &str) → Result<String> | Hash bcrypt via spawn_blocking. Coût configurable via BCRYPT_COST (défaut : 12). |
verify_password | async (password: &str, hash: &str) → Result<bool> | Vérification bcrypt via spawn_blocking. |
generate_secure_password | () → String | Génère un mot de passe de 20 caractères avec mix garanti. |
TotpService
Module : rustwarden_core::services::totp_service
| Méthode | Description |
|---|---|
setup_totp(db, user_id, username, issuer) | Génère un secret TOTP + QR code URI. |
verify_and_enable(db, user_id, code) | Vérifie un code et active le 2FA. Retourne les 10 codes de secours. |
verify_code(db, user_id, code) | Vérifie un code TOTP (6 chiffres). |
verify_backup_code(db, user_id, code) | Vérifie un code de secours (8 chars, usage unique). |
disable_totp(db, user_id) | Désactive le 2FA. |
create_challenge(db, user_id) | Crée un challenge 2FA (token temporaire, 5 min, max 5 tentatives). |
validate_challenge(db, challenge_token) | Valide un challenge. |
consume_challenge(db, challenge_token) | Marque un challenge comme consommé. |
RoleService / PermissionService
Module : rustwarden_core::services::role_service — Export : prélude
| Méthode | Description |
|---|---|
RoleService::create_role(db, name, description) | Crée un rôle. |
RoleService::get_role_by_name(db, name) | Recherche par nom. |
RoleService::list_all_roles(db) | Liste tous les rôles. |
RoleService::initialize_default_roles(db) | Seed admin, user, app_manager. Idempotent. |
PermissionService::get_permissions_for_user(db, user_id) | Union des permissions de tous les rôles. |
PermissionService::set_role_permissions(db, role_id, perm_ids) | Remplace atomiquement les permissions d'un rôle. |
PermissionService::initialize_default_permissions(db) | Seed les 12 permissions par défaut. Idempotent. |
ResourceService
Module : rustwarden_core::services::resource_service — Export : prélude
Système générique de registre de ressources et de partage.
Hiérarchie des permissions : read < write < admin
| Méthode | Description |
|---|---|
register(db, resource_type, resource_id, owner_id) | Enregistre une ressource dans le registre. |
set_public(db, resource_type, resource_id, is_public) | Bascule la visibilité publique. |
unregister(db, resource_type, resource_id) | Supprime du registre (cascade sur les partages). |
share(db, resource_type, resource_id, shared_with_user_id, permission_level, shared_by_user_id) | Partage une ressource. Met à jour si déjà partagé. |
revoke_share(db, share_id) | Révoque un partage par ID. |
user_can_access(db, user_id, resource_type, resource_id, required_level) | Vérifie l'accès : owner → public+read → partagé. |
effective_permission(db, user_id, resource_type, resource_id) | Retourne "owner", le niveau de partage, "read" (public), ou None. |
accessible_by_user(db, user_id, resource_type) | Toutes les ressources accessibles (possédées + partagées + publiques). |
RefreshTokenService
Module : rustwarden_core::services::refresh_token_service
| Méthode | Description |
|---|---|
create_refresh_token(db, user_id, expiration_days) | Crée un refresh token. Révoque les plus anciens si > 10 actifs (SEC-M4). |
validate_refresh_token(db, token) | Valide un token (hash SHA-256, existence, non révoqué, non expiré). |
revoke_all_tokens_for_user(db, user_id) | Révoque toutes les sessions (logout, changement de mot de passe). |
list_user_sessions(db, user_id) | Liste les sessions actives. |
revoke_session(db, token_id) | Révoque une session spécifique. |
AppSettingsService
Module : rustwarden_core::services::app_settings_service
| Méthode | Description |
|---|---|
get_setting(db, key) | Lire un paramètre. |
set_setting(db, key, value, updated_by) | Créer ou mettre à jour un paramètre. |
get_bool(db, key, default) | Lire un booléen avec valeur par défaut. |
initialize_default_settings(db) | Seed ~30 paramètres par défaut. Idempotent. |
Services gitrust-core
RepositoryService
Module : gitrust_core::services::repository_service
| Méthode | Signature | Description |
|---|---|---|
create | (db, owner_id, slug, description, is_public) → Result<repository::Model> | Crée un dépôt + répertoire bare sur disque. Enregistre dans ResourceService. |
find_by_owner_and_slug | (db, owner_username, slug) → Result<Option<repository::Model>> | Recherche par owner/slug (chemin URL). |
list_by_owner | (db, owner_id) → Result<Vec<repository::Model>> | Dépôts d'un propriétaire. |
update | (db, repo_id, owner_id, description, default_branch) → Result<repository::Model> | Met à jour les métadonnées. Anti-IDOR. |
delete | (db, repo_id, owner_id) → Result<()> | Supprime DB + bare repo sur disque. Anti-IDOR. |
mark_non_empty | (db, repo_id) → Result<()> | Passe is_empty = false après le premier push. |
SshKeyService
Module : gitrust_core::services::ssh_key_service
| Méthode | Signature | Description |
|---|---|---|
create | (db, user_id, title, key_data) → Result<ssh_key::Model> | Parse la clé, calcule le fingerprint SHA256, valide le type (ed25519, rsa ≥ 4096 bits, ecdsa-p256/p384). |
list_by_user | (db, user_id) → Result<Vec<ssh_key::Model>> | Liste les clés d'un utilisateur. |
find_by_fingerprint | (db, fingerprint) → Result<Option<ssh_key::Model>> | Recherche par empreinte (utilisé par le serveur SSH). |
delete | (db, key_id, user_id) → Result<()> | Suppression avec vérification d'ownership. |
update_last_used | (db, key_id) → Result<()> | Met à jour last_used_at à chaque authentification SSH. |
IssueService
Module : gitrust_core::services::issue_service
| Méthode | Description |
|---|---|
create(db, repo_id, author_id, title, body, label_ids, subject_names) | Numéro auto-incrémenté par dépôt. |
list(db, repo_id, state_filter, label_filter, page, per_page) | Liste paginée avec filtres. |
find_by_number(db, repo_id, number) | Par numéro d'issue. |
close(db, issue_id, closed_by) | Ferme l'issue + audit. |
reopen(db, issue_id) | Rouvre l'issue + audit. |
enrich_issue(db, issue) | Enrichit avec username auteur, labels, nombre de commentaires. |
LabelService
Module : gitrust_core::services::label_service
| Méthode | Description |
|---|---|
create_classification(db, owner_id, name, color, description) | Label scope owner (tous ses dépôts). |
create_subject(db, repo_id, name, color) | Label scope dépôt. Couleur défaut #6b7280. |
find_or_create_subject(db, repo_id, name) | Trouve ou crée (pour création inline dans les issues). |
list_classification_by_owner(db, owner_id) | Labels classification de l'owner. |
list_subject_by_repo(db, repo_id) | Labels subject du dépôt. |
search_subject(db, repo_id, query, limit) | Recherche préfixe (autocomplete HTMX). |
assign_to_issue(db, issue_id, label_id) | Association issue ↔ label. |
TeamService
Module : gitrust_core::services::team_service
| Méthode | Description |
|---|---|
create(db, owner_id, slug, description) | Crée une équipe. |
add_member(db, team_id, user_id, role) | Ajoute un membre. |
remove_member(db, team_id, user_id) | Retire un membre. |
grant_repo_access(db, team_id, repo_id, permission) | Accorde l'accès à un dépôt (read/write/admin). |
revoke_repo_access(db, team_id, repo_id) | Révoque l'accès. |
ImportService
Module : gitrust_core::services::import_service
| Méthode | Description |
|---|---|
create_job(db, owner_id, source_url, target_slug) | Crée un job pending dans import_jobs. |
mark_running(db, job_id) | Passe en running + started_at. |
update_progress(db, job_id, received, total, bytes) | Met à jour les compteurs de progression. |
mark_success(db, job_id, repo_id) | Lie le job au dépôt créé. |
mark_failed(db, job_id, error_message) | Enregistre l'échec. |
mark_cancelled(db, job_id) | Annulation. |
Gestion des erreurs
AppError (rustwarden-core)
| Variante | HTTP | Usage |
|---|---|---|
AppError::NotFound(msg) | 404 | Ressource introuvable |
AppError::Validation(msg) | 400 | Données invalides |
AppError::Forbidden | 403 | Accès refusé (RBAC) |
AppError::Unauthorized | 401 | Non authentifié |
AppError::TokenExpired | 401 | JWT expiré |
AppError::TokenReused | 401 | Refresh token réutilisé (attaque détectée) |
AppError::Conflict(msg) | 409 | Contrainte d'unicité violée |
AppError::Internal(msg) | 500 | Erreur interne |
GitrustError (gitrust-core)
Mêmes variantes que AppError avec GitrustError::Database(sea_orm::DbErr) en plus pour les erreurs SeaORM non mappées.
Patterns communs
Accès à un service depuis un handler
use gitrust_core::services::issue_service::IssueService; async fn list_issues_handler( State(db): State<DatabaseConnection>, user: AuthUser, ) -> Result<impl IntoResponse, AppError> { let issues = IssueService::list(&db, repo_id, "open", None, 1, 30).await?; // ... }
Vérification d'ownership systématique (anti-IDOR)
// Toujours passer owner_id au service — le service vérifie en interne let repo = RepositoryService::find_by_owner_and_slug(&db, &owner, &repo_slug).await?; // Puis vérifier que l'utilisateur courant peut accéder if !ResourceService::user_can_access(&db, user.user_id, "repository", repo.id, "read").await? { return Err(AppError::Forbidden); }
GitRust