services-api-interne.md 12995 octets

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éthodeSignatureDescription
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éthodeSignatureDescription
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éthodeSignatureDescription
hash_passwordasync (password: &str) → Result<String>Hash bcrypt via spawn_blocking. Coût configurable via BCRYPT_COST (défaut : 12).
verify_passwordasync (password: &str, hash: &str) → Result<bool>Vérification bcrypt via spawn_blocking.
generate_secure_password() → StringGénère un mot de passe de 20 caractères avec mix garanti.

TotpService

Module : rustwarden_core::services::totp_service

MéthodeDescription
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éthodeDescription
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éthodeDescription
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éthodeDescription
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éthodeDescription
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éthodeSignatureDescription
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éthodeSignatureDescription
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éthodeDescription
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éthodeDescription
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éthodeDescription
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éthodeDescription
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)

VarianteHTTPUsage
AppError::NotFound(msg)404Ressource introuvable
AppError::Validation(msg)400Données invalides
AppError::Forbidden403Accès refusé (RBAC)
AppError::Unauthorized401Non authentifié
AppError::TokenExpired401JWT expiré
AppError::TokenReused401Refresh token réutilisé (attaque détectée)
AppError::Conflict(msg)409Contrainte d'unicité violée
AppError::Internal(msg)500Erreur 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