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) ou Result<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_serviceExport : 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_serviceExport : 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_serviceExport : 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);
}

Voir aussi