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¶
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_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);
}