veza/veza-chat-server/AUDIT_CHAT_SERVER_RUST.md
2025-12-03 20:33:26 +01:00

32 KiB

🔍 AUDIT TECHNIQUE EXHAUSTIF - CHAT SERVER RUST

Veza/Talas - Serveur de Chat Temps-Réel

Date: 2025-01-27
Version analysée: 0.2.0
Auditeur: Auto (AI Agent)
Durée audit: Exhaustif multi-phases


📋 SECTION 1 : RÉSUMÉ EXÉCUTIF

État Global du Projet

Composant État Complétude Notes
WebSocket Server 🟡 Partiel 65% Framework Axum OK, auth JWT présente mais incomplète
Messages 1-to-1 🟢 Fonctionnel 80% Implémenté via conversations, persistence OK
Group Chat/Channels 🟡 Partiel 50% Structure présente, permissions incomplètes
Typing Indicators 🟢 Fonctionnel 75% Implémenté, timeout 3s, cleanup présent
Read Receipts 🟡 Partiel 40% Structure DB présente, logique TODO ligne 258
Presence 🟢 Fonctionnel 70% Online/Away/Busy/Offline, multi-device partiel
Modération 🟡 Partiel 60% Auto-modération basique, sanctions DB présentes
Performance 🟡 À améliorer 55% Pas de benchmarks, optimisations manquantes
Sécurité 🟠 Critique 45% Auth WebSocket OK, rate limiting présent, validation input partielle
Tests 🔴 Insuffisant 25% Tests unitaires rares, integration tests ignorés
Documentation 🟡 Partielle 40% Doc comments présents, exemples manquants

Top 10 Problèmes Critiques

  1. 🔴 P0 - Auth WebSocket Token dans Query Params : Token JWT exposé dans URL (ligne 43 main.rs)
  2. 🔴 P0 - Read Receipts Non Implémentés : TODO ligne 258 websocket/handler.rs
  3. 🔴 P0 - Tests Coverage < 30% : Tests d'intégration ignorés, unitaires rares
  4. 🟠 P1 - Clippy Warnings Non Résolus : 10+ warnings compilation (unused imports, PartialEq manquant)
  5. 🟠 P1 - Rate Limiting Non Appliqué : DosProtectionManager présent mais non utilisé dans handler
  6. 🟠 P1 - Validation Input Messages : Pas de sanitization XSS, longueur max non vérifiée
  7. 🟠 P1 - Heartbeat/Ping-Pong Incomplet : Ping géré, mais pas de timeout idle connections
  8. 🟡 P2 - Modération Auto Basique : Détection spam simpliste (similarité Levenshtein)
  9. 🟡 P2 - Pas de Redis Pub/Sub : Broadcast limité à instance unique (pas de scaling horizontal)
  10. 🟡 P2 - Metrics Prometheus Non Utilisées : Métriques définies mais non enregistrées dans handlers

Effort Total Correction Estimé

  • P0 (Bloquants): 3-5 jours
  • P1 (Critiques): 5-7 jours
  • P2 (Majeurs): 7-10 jours
  • P3 (Mineurs): 3-5 jours
  • TOTAL: 18-27 jours (3.5-5 semaines)

📊 SECTION 2 : CARTOGRAPHIE

2.1 Arborescence Rust

veza-chat-server/
├── src/
│   ├── main.rs                    ✅ Point d'entrée (Axum server)
│   ├── lib.rs                     ✅ Library root
│   ├── config.rs                  ✅ Configuration (env vars)
│   ├── error.rs                   ✅ Error types (thiserror)
│   ├── jwt_manager.rs              ✅ JWT avec refresh tokens
│   ├── websocket/
│   │   ├── mod.rs                 ✅ Types messages WS
│   │   ├── handler.rs             ⚠️ Handler WS (auth query param)
│   │   └── broadcast.rs           ✅ Broadcast manager
│   ├── repository/
│   │   ├── message_repository.rs  ✅ CRUD messages (SQLx)
│   │   └── room_repository.rs     ✅ CRUD rooms
│   ├── models/
│   │   └── message.rs             ✅ Modèle Message (UUID)
│   ├── services/
│   │   └── room_service.rs        ✅ Service rooms
│   ├── auth.rs                    ⚠️ Auth manager (non utilisé)
│   ├── authentication.rs          ⚠️ Auth alternatif (non utilisé)
│   ├── typing_indicator.rs        ✅ Typing indicators
│   ├── read_receipts.rs           ⚠️ Read receipts (i64 au lieu UUID)
│   ├── presence.rs                ✅ Presence manager
│   ├── moderation.rs              ⚠️ Modération (i32 user_id)
│   ├── rate_limiter.rs            ⚠️ Rate limiter (non utilisé)
│   ├── prometheus_metrics.rs      ⚠️ Metrics définies mais non utilisées
│   ├── event_bus.rs               ✅ RabbitMQ EventBus
│   ├── database/
│   │   └── pool.rs                ✅ Pool PostgreSQL
│   ├── security/
│   │   └── csrf.rs                ✅ CSRF tokens
│   ├── core/                      ⚠️ Modules non utilisés (duplication?)
│   └── hub/                       ⚠️ Modules non utilisés (duplication?)
├── migrations/
│   ├── 001_create_clean_database.sql  ✅ Schéma base
│   └── 002_advanced_features.sql      ✅ Features avancées
├── tests/
│   └── integration_test.rs        ⚠️ Tests ignorés (#[ignore])
├── Cargo.toml                     ✅ Dépendances complètes
└── env.example                     ✅ Configuration exemple

Problèmes détectés:

  • Duplication: auth.rs vs authentication.rs vs jwt_manager.rs
  • Modules non utilisés: core/, hub/ (code mort?)
  • Incohérence types: i32 vs UUID (read_receipts, moderation)

2.2 Dépendances Cargo

Catégorie Dépendance Version État Notes
Runtime tokio 1.35 Full features
WebSocket axum 0.8 Framework moderne
WebSocket tokio-tungstenite 0.21 Core WS
Database sqlx 0.8.6 PostgreSQL, macros
Cache redis 0.32 ⚠️ Optional, non utilisé
Auth jsonwebtoken 9.2 JWT
Serialization serde 1.0 JSON
Logging tracing 0.1 Structured logging
Metrics metrics 0.22 ⚠️ Optional, non utilisé
gRPC tonic 0.11 ⚠️ Présent mais non utilisé
Event Bus lapin 2.3 RabbitMQ
Validation validator 0.20 ⚠️ Présent mais non utilisé
Security bcrypt 0.17 ⚠️ Présent mais non utilisé

Problèmes:

  • Dépendances optionnelles non utilisées (redis, metrics, validator)
  • gRPC présent mais serveur non démarré dans main.rs
  • Versions à jour

2.3 Configuration

Fichiers config:

  • env.example : Complet (131 lignes)
  • .env : Présent (non lu pour audit)
  • config.rs : Chargement depuis env vars

Paramètres hardcodés:

  • main.rs:162 : JWT secret par défaut hardcodé (fallback)
  • typing_indicator.rs:19 : Timeout 3s hardcodé
  • rate_limiter.rs:138 : MAX_MESSAGES_PER_MINUTE = 60 hardcodé

Secrets management:

  • ⚠️ JWT secret dans env var (pas de vault)
  • ⚠️ Pas de rotation automatique secrets

SECTION 3 : WEBSOCKET & PROTOCOLE

3.1 Serveur WebSocket

Framework: Axum 0.8 avec ws feature

Architecture:

  • Single-threaded tokio runtime (par défaut)
  • Connection pooling via WebSocketManager (Vec<Arc>)
  • Broadcast via broadcast.rs (tokio::sync::broadcast channels)
  • State: Arc<RwLock<>> pour clients

Gestion connections:

  • Handshake WebSocket via Axum WebSocketUpgrade
  • ⚠️ PROBLÈME P0: Token JWT dans query params (ligne 43 handler.rs)
  • Ping/Pong implémenté (lignes 129-138 handler.rs)
  • Pas de timeout idle connections automatique
  • Pas de heartbeat périodique (seulement ping client-initiated)

Code problématique:

// src/websocket/handler.rs:43
let token = match params.get("token") {
    Some(t) => t,
    None => {
        error!("❌ Token manquant");
        return (StatusCode::UNAUTHORIZED, "Missing token").into_response();
    }
};

Impact: Token exposé dans logs serveur, URL, historique navigateur.

3.2 Protocole Messages

Format: JSON via serde_json

Schéma messages:

// IncomingMessage (src/websocket/mod.rs:24)
pub enum IncomingMessage {
    SendMessage { conversation_id, content, parent_message_id },
    JoinConversation { conversation_id },
    LeaveConversation { conversation_id },
    MarkAsRead { conversation_id, message_id },
    Ping,
}

// OutgoingMessage (src/websocket/mod.rs:47)
pub enum OutgoingMessage {
    NewMessage { conversation_id, message_id, sender_id, content, created_at },
    ActionConfirmed { action, success },
    Error { message },
    Pong,
}

Validation:

  • Deserialization avec serde_json::from_str
  • ⚠️ Pas de validation longueur message (MAX_MESSAGE_LENGTH non appliqué)
  • Pas de sanitization XSS (ammonia présent mais non utilisé)
  • Pas de validation conversation_id (existence, permissions)

3.3 Authentification WebSocket

Mécanisme: JWT dans query params ⚠️

Validation:

  • JwtManager::validate_access_token (ligne 52 handler.rs)
  • Claims extraits (AccessTokenClaims)
  • ⚠️ Pas de refresh token support dans WS
  • Pas de validation permissions conversation

Failles:

  1. Token dans URL (exposé logs, cache, referrer)
  2. Pas de validation conversation access avant join
  3. Pas de rate limiting par user_id (seulement par connection_id)

💬 SECTION 4 : FONCTIONNALITÉS CHAT

4.1 Messages 1-to-1

Feature Status Implémentation Notes
Envoi message direct MessageRepository::create UUID-based
Réception temps-réel broadcast_to_conversation Via WebSocket
Historique messages get_conversation_messages Pagination LIMIT
Chiffrement E2E Absent Non implémenté

Code:

// src/repository/message_repository.rs:18
pub async fn create(
    &self,
    conversation_id: Uuid,
    sender_id: Uuid,
    content: &str,
) -> Result<Message>

Gaps:

  • Pas de chiffrement end-to-end
  • Pagination basique (LIMIT/OFFSET, pas de cursor)
  • Pas de recherche full-text

4.2 Group Chat & Channels

Feature Status Implémentation Notes
Création groupe RoomService::create_room UUID-based
Ajout membres RoomService::add_user Via conversation_members
Suppression membres RoomService::remove_user
Permissions ⚠️ Partiel Rôles présents, vérification incomplète
Broadcast messages broadcast_to_conversation
Historique groupe get_conversation_messages

Permissions:

  • Rôles définis: admin, moderator, member (migration 001)
  • ⚠️ Vérification permissions non appliquée dans handler WS

4.3 Features Temps-Réel

Typing Indicators

Status: Fonctionnel (75%)

Implémentation:

  • TypingIndicatorManager (src/typing_indicator.rs)
  • Timeout: 3s (hardcodé ligne 19)
  • Cleanup périodique présent
  • ⚠️ Pas de broadcast WebSocket intégré (manager isolé)

Code:

// src/typing_indicator.rs:25
pub async fn set_typing(&self, conversation_id: &str, user_id: &str)

Gaps:

  • Pas de message WebSocket pour typing events
  • Timeout non configurable
  • Pas de debouncing côté client

Read Receipts

Status: 🟡 Partiel (40%)

Implémentation:

  • Structure DB présente (read_receipts table)
  • ReadReceiptManager présent (src/read_receipts.rs)
  • PROBLÈME P0: TODO ligne 258 websocket/handler.rs
  • ⚠️ Types incohérents: i64 au lieu de UUID

Code problématique:

// src/websocket/handler.rs:249
IncomingMessage::MarkAsRead { conversation_id, message_id } => {
    debug!("👁️ Client {} marque le message {} comme lu", client.id, message_id);
    // TODO: Implémenter la logique de marquage comme lu
    let outgoing = OutgoingMessage::ActionConfirmed {
        action: "marked_as_read".to_string(),
        success: true,
    };
    client.send_message(outgoing).await?;
}

Gaps:

  • Logique non implémentée
  • Pas de synchronisation multi-device
  • Pas de UI double-check marks

Presence

Status: Fonctionnel (70%)

Implémentation:

  • PresenceManager (src/presence.rs)
  • Statuts: Online, Away, Busy, Invisible, Offline
  • Cleanup inactifs (5 min threshold)
  • ⚠️ Pas de persistence DB (mémoire uniquement)
  • ⚠️ Pas de broadcast WebSocket intégré

4.4 Modération

Feature Status Implémentation Notes
Détection spam ⚠️ Basique Similarité Levenshtein simplifiée
Blocage users ModerationSystem::apply_sanction DB présente
Suppression messages MessageRepository::delete Soft delete (is_deleted)
Modération auto ⚠️ Basique Seuil 3 messages similaires
Logs modération Tracing + DB Audit trail présent

Code modération auto:

// src/moderation.rs:270
async fn detect_spam(&self, user_id: i32, content: &str) -> Result<bool> {
    // Vérifier les messages répétitifs (5 dernières minutes)
    let similar_count = recent_messages.iter()
        .filter(|row| {
            let msg_content: String = row.get("content");
            self.calculate_similarity(content, &msg_content) > 0.8
        })
        .count();
    Ok(similar_count >= 3)
}

Problèmes:

  • Détection spam trop simpliste
  • Pas de ML/AI (TODO ligne 329 security.rs)
  • Incohérence types: i32 user_id au lieu UUID

🚀 SECTION 5 : PERFORMANCE

5.1 Benchmarks

Status: Absent

  • Pas de dossier benches/
  • Criterion présent dans Cargo.toml mais non utilisé
  • Pas de métriques de performance documentées

Recommandation: Créer benchmarks pour:

  • Messages/seconde supportés
  • Latence p50/p95/p99
  • Concurrent connections max
  • Memory usage par connection

5.2 Gestion Mémoire

Allocations:

  • ⚠️ Clones excessifs: OutgoingMessage::clone() ligne 144 websocket/mod.rs
  • Arc<RwLock<>> utilisé correctement
  • ⚠️ Vec<Arc> dans WebSocketManager (croissance linéaire)

Lifetimes:

  • Lifetimes Rust corrects (pas de dangling refs)
  • ⚠️ Pas de vérification memory leaks (tests manquants)

Buffer sizes:

  • ⚠️ Pas de limite taille message WebSocket (64KB max recommandé)
  • ⚠️ Pas de backpressure handling

5.3 Concurrence

Tokio:

  • Async/await partout
  • ⚠️ Pas de spawn_blocking() pour opérations CPU-intensive
  • Channels utilisés (tokio::sync::broadcast)

Deadlocks potentiels:

  • ⚠️ Ordre locks: WebSocketManager::clients puis client.conversations (ligne 141 websocket/mod.rs)
  • ⚠️ Pas de timeout sur locks (RwLock peut bloquer indéfiniment)

Race conditions:

  • ⚠️ WebSocketManager::remove_client peut race avec broadcast_to_conversation

5.4 Scalabilité

Horizontal scaling:

  • Pas de Redis pub/sub pour multi-instances
  • Broadcast limité à instance unique
  • ⚠️ RabbitMQ EventBus présent mais non utilisé pour broadcast

Session sticky:

  • Pas de support load balancer aware
  • ⚠️ Pas de session externalisée (Redis)

Graceful shutdown:

  • ⚠️ Pas de drain connections
  • ⚠️ Pas de timeout shutdown

🔒 SECTION 6 : SÉCURITÉ

6.1 Validation Input

Handlers WebSocket:

  • ⚠️ Message length: Pas de vérification MAX_MESSAGE_LENGTH (2000 chars config)
  • Sanitization XSS: ammonia présent mais non utilisé
  • ⚠️ Injection: SQLx prepared statements (protection SQL)
  • File upload: Non implémenté (feature flag présent)

Code problématique:

// src/websocket/handler.rs:170
IncomingMessage::SendMessage { conversation_id, content, parent_message_id } => {
    // Pas de validation longueur content
    // Pas de sanitization XSS
    let message = state.message_repo.create(conversation_id, sender_uuid, &content).await?;
}

6.2 Rate Limiting

Implémentation:

  • DosProtectionManager présent (src/rate_limiter.rs)
  • PROBLÈME P1: Non utilisé dans websocket/handler.rs
  • Rate limiting par user_id et IP
  • ⚠️ Configuration hardcodée (60 msg/min)

Code manquant:

// src/websocket/handler.rs devrait avoir:
let dos_manager = state.dos_manager.clone();
if !dos_manager.check_message_allowed(claims.user_id).await? {
    return Err(ChatError::rate_limit_error("Rate limit exceeded"));
}

6.3 Chiffrement

TLS/WSS:

  • ⚠️ Pas de configuration TLS dans main.rs
  • ⚠️ ENABLE_TLS=false dans env.example
  • Pas de certificats validation

End-to-end encryption:

  • Non implémenté
  • Pas de Signal Protocol ou équivalent

Storage at-rest:

  • ⚠️ Messages en clair dans PostgreSQL
  • ⚠️ Pas de chiffrement colonnes sensibles

6.4 Audit Sécurité Rust

Clippy:

cargo clippy --all-targets --all-features -- -D warnings

Résultats:

  • 10+ warnings (unused imports, PartialEq manquant)
  • Pas de unsafe blocks (bon )

Cargo audit:

  • ⚠️ Non exécuté (recommandé: cargo audit)

Vulnérabilités connues:

  • À vérifier avec cargo audit

💾 SECTION 7 : PERSISTENCE

7.1 Stockage Messages

Backend: PostgreSQL via SQLx

Schéma:

  • Table messages (UUID-based)
  • Index: conversation_id, sender_id, created_at
  • Soft delete: is_deleted BOOLEAN
  • ⚠️ Pas de partitioning par date
  • ⚠️ Pas de retention policy (purge old messages)

Migrations:

  • 001_create_clean_database.sql
  • 002_advanced_features.sql
  • Schéma complet et cohérent

7.2 Queries Database

N+1 queries:

  • ⚠️ Potentiel dans get_conversation_messages (pas de JOIN users)
  • Pagination présente (LIMIT)

Prepared statements:

  • SQLx query! macros utilisées
  • Protection injection SQL

Queries lentes:

  • ⚠️ Pas d'EXPLAIN ANALYZE effectué
  • ⚠️ Pas de monitoring query duration

7.3 Cache Strategy

Redis:

  • ⚠️ Dépendance présente mais non utilisée
  • Pas de cache recent messages
  • Pas de cache user online status
  • Pas de cache typing indicators
  • Pas de pub/sub pour broadcast multi-instances

Recommandation: Implémenter cache Redis pour:

  • Messages récents (TTL 1h)
  • User presence (TTL 5min)
  • Typing indicators (TTL 10s)

SECTION 8 : QUALITÉ CODE

8.1 Linting

Clippy violations (catégorisées):

Catégorie Count Exemples
Correctness 2 PartialEq manquant SslMode
Performance 0 Aucun
Style 8 Unused imports
Complexity 0 Aucun

Fichiers problématiques:

  • src/config.rs: Unused imports Pool, Postgres, error
  • src/event_bus.rs: Unused imports ExchangeDeclareOptions, LapinError, ExchangeKind
  • src/websocket/handler.rs: Unused import SinkExt, SimpleMessageStore
  • src/config.rs:552: SslMode manque #[derive(PartialEq)]

8.2 Formatting

Status: ⚠️ Non vérifié

Recommandation: Exécuter cargo fmt --check

8.3 Tests

Coverage estimé: 25%

Tests présents:

  • tests/integration_test.rs: 6 tests, tous #[ignore]
  • Tests unitaires: Rares (typing_indicator, jwt_manager, rate_limiter)

Modules sans tests:

  • websocket/handler.rs
  • repository/message_repository.rs
  • services/room_service.rs
  • moderation.rs
  • presence.rs

Objectif ORIGIN_: 75%+ coverage (non atteint)

8.4 Documentation

Doc comments:

  • Présents sur modules principaux (//!)
  • ⚠️ Manquants sur fonctions publiques
  • Pas d'exemples dans doc (#[doc = include_str!("...")])

Cargo doc:

  • ⚠️ Non généré (recommandé: cargo doc --no-deps --open)

📈 SECTION 9 : OBSERVABILITÉ

9.1 Logging

Framework: tracing

Structured logging:

  • Utilisé partout
  • Niveaux: trace/debug/info/warn/error
  • ⚠️ Pas de logs sensibles détectés (tokens, passwords)

Configuration:

  • JSON en production (ligne 106 main.rs)
  • Debug en dev (ligne 109 main.rs)

9.2 Metrics

Prometheus:

  • PrometheusMetrics défini (src/prometheus_metrics.rs)
  • PROBLÈME P2: Métriques non enregistrées dans handlers
  • Endpoint /metrics présent (ligne 203 main.rs)

Métriques manquantes:

  • Messages/seconde non enregistrés
  • Latence messages non mesurée
  • Erreurs non comptées

9.3 Tracing

OpenTelemetry:

  • Non implémenté
  • Pas de spans (connection lifecycle, message flow)
  • Pas de trace_id propagation

🔗 SECTION 10 : INTÉGRATION

10.1 API REST

Endpoints exposés:

  • GET /health
  • GET /healthz (liveness)
  • GET /readyz (readiness)
  • GET /metrics (Prometheus)
  • GET /api/messages/{conversation_id}
  • POST /api/messages
  • GET /api/messages/stats ⚠️ (hardcodé)

Cohérence avec backend Go:

  • ⚠️ Non vérifiée (backend Go non analysé)

10.2 Communication Inter-Services

RabbitMQ EventBus:

  • RabbitMQEventBus présent (src/event_bus.rs)
  • ⚠️ Initialisé dans main.rs mais non utilisé pour events
  • Retry logic présent
  • ⚠️ Pas de circuit breaker

gRPC:

  • ⚠️ grpc_server.rs présent mais non démarré
  • ⚠️ grpc_client.rs présent mais non utilisé

10.3 Authentification Partagée

JWT shared secret:

  • JWT_SECRET env var
  • ⚠️ Fallback hardcodé (ligne 162 main.rs)
  • Même algorithme (HS256 par défaut)
  • ⚠️ Audience/Issuer configurables

Incohérences:

  • ⚠️ Non vérifiées (backend Go non analysé)

📐 SECTION 11 : GAP ANALYSIS ORIGIN_

11.1 Matrice Complétude Features

Feature ORIGIN_ Status Complétude Gaps
WebSocket temps-réel 80% Heartbeat timeout, idle connections
Messages 1-to-1 80% E2E encryption manquant
Group chat 70% Permissions incomplètes
Channels ⚠️ 50% Structure présente, features manquantes
Typing indicators 75% Broadcast WS manquant
Read receipts 🟡 40% TODO ligne 258
Presence 70% Persistence DB manquante
Modération auto ⚠️ 60% ML/AI manquant
Rate limiting ⚠️ 50% Non appliqué dans handler
Redis pub/sub 0% Non implémenté
Metrics Prometheus ⚠️ 30% Définies mais non utilisées
Tests coverage 75%+ 25% Tests ignorés, unitaires rares

11.2 Écarts Architecture

ORIGIN_ attendu:

  • Event-driven via RabbitMQ (présent mais non utilisé)
  • Redis pub/sub pour scaling (non implémenté)
  • gRPC inter-services ⚠️ (présent mais non démarré)

Architecture réelle:

  • WebSocket direct (Axum)
  • Broadcast in-memory (tokio::sync::broadcast)
  • Pas de scaling horizontal

🎯 SECTION 12 : PLAN D'ACTION PRIORISÉ

RUST-CHAT-001 | Auth WebSocket Token dans Query Params

├─ Gravité     : 🔴 P0 - BLOQUANT
├─ Description : Token JWT exposé dans URL query params (ligne 43 handler.rs)
├─ Impact      : Token visible dans logs, cache navigateur, referrer headers
├─ Effort      : 2-3 heures
├─ Dépendances : Aucune
└─ Action      : Déplacer token dans header Authorization ou cookie HTTP-only

Solution:

// Avant (handler.rs:43)
let token = params.get("token")?;

// Après
let auth_header = request.headers().get("authorization")?;
let token = extract_token_from_header(auth_header.to_str()?)?;

RUST-CHAT-002 | Read Receipts Non Implémentés

├─ Gravité     : 🔴 P0 - BLOQUANT
├─ Description : TODO ligne 258 websocket/handler.rs - logique marquage comme lu absente
├─ Impact      : Feature read receipts non fonctionnelle
├─ Effort      : 1 jour
├─ Dépendances : ReadReceiptManager présent mais types i64 vs UUID
└─ Action      : Implémenter logique + corriger types UUID

Solution:

// handler.rs:249
IncomingMessage::MarkAsRead { conversation_id, message_id } => {
    let read_receipt_manager = state.read_receipt_manager.clone();
    read_receipt_manager.mark_as_read(
        message_id,
        claims.user_id.parse()?,
        conversation_id
    ).await?;
    // Broadcast read receipt to conversation
    state.ws_manager.broadcast_read_receipt(conversation_id, message_id, claims.user_id).await?;
}

RUST-CHAT-003 | Tests Coverage < 30%

├─ Gravité     : 🔴 P0 - BLOQUANT
├─ Description : Tests d'intégration ignorés, unitaires rares
├─ Impact      : Pas de confiance dans refactoring, bugs non détectés
├─ Effort      : 5-7 jours
├─ Dépendances : Setup DB de test
└─ Action      : Activer tests integration, ajouter tests unitaires critiques

Actions:

  1. Retirer #[ignore] des tests integration
  2. Ajouter tests unitaires: websocket/handler.rs, message_repository.rs
  3. Setup CI/CD avec coverage reporting (tarpaulin)

RUST-CHAT-004 | Clippy Warnings Non Résolus

├─ Gravité     : 🟠 P1 - CRITIQUE
├─ Description : 10+ warnings compilation (unused imports, PartialEq manquant)
├─ Impact      : Code quality dégradée, warnings masquent vrais problèmes
├─ Effort      : 1-2 heures
├─ Dépendances : Aucune
└─ Action      : Corriger tous les warnings clippy

Actions:

  1. Supprimer unused imports
  2. Ajouter #[derive(PartialEq)] à SslMode
  3. Ajouter #[allow(dead_code)] si nécessaire (temporaire)

RUST-CHAT-005 | Rate Limiting Non Appliqué

├─ Gravité     : 🟠 P1 - CRITIQUE
├─ Description : DosProtectionManager présent mais non utilisé dans handler
├─ Impact      : Pas de protection DoS, spam possible
├─ Effort      : 2-3 heures
├─ Dépendances : DosProtectionManager présent
└─ Action      : Intégrer rate limiting dans websocket handler

Solution:

// Ajouter dans WebSocketState
pub dos_manager: Arc<DosProtectionManager>,

// Dans handle_incoming_message
if !state.dos_manager.check_message_allowed(claims.user_id.parse()?).await? {
    return Err(ChatError::rate_limit_error("Rate limit exceeded"));
}

RUST-CHAT-006 | Validation Input Messages

├─ Gravité     : 🟠 P1 - CRITIQUE
├─ Description : Pas de sanitization XSS, longueur max non vérifiée
├─ Impact      : XSS possible, DoS via messages géants
├─ Effort      : 1 jour
├─ Dépendances : ammonia présent, validator présent
└─ Action      : Ajouter validation longueur + sanitization XSS

Solution:

// handler.rs:170
const MAX_MESSAGE_LENGTH: usize = 2000;
if content.len() > MAX_MESSAGE_LENGTH {
    return Err(ChatError::validation_error("Message too long"));
}
let sanitized = ammonia::clean(content);
let message = state.message_repo.create(conversation_id, sender_uuid, &sanitized).await?;

RUST-CHAT-007 | Heartbeat/Ping-Pong Incomplet

├─ Gravité     : 🟠 P1 - CRITIQUE
├─ Description : Ping géré, mais pas de timeout idle connections
├─ Impact      : Connections zombies consomment ressources
├─ Effort      : 1 jour
├─ Dépendances : Aucune
└─ Action      : Implémenter timeout idle + heartbeat périodique

Solution:

// Ajouter dans handle_socket
let mut last_ping = Instant::now();
const IDLE_TIMEOUT: Duration = Duration::from_secs(300); // 5 min

tokio::select! {
    msg = receiver.next() => { /* ... */ },
    _ = tokio::time::sleep(Duration::from_secs(30)) => {
        // Heartbeat périodique
        if last_ping.elapsed() > IDLE_TIMEOUT {
            break; // Timeout
        }
        client.send_message(OutgoingMessage::Ping).await?;
    }
}

RUST-CHAT-008 | Modération Auto Basique

├─ Gravité     : 🟡 P2 - MAJEUR
├─ Description : Détection spam simpliste (similarité Levenshtein)
├─ Impact      : Faux positifs/négatifs, spam non détecté
├─ Effort      : 3-5 jours
├─ Dépendances : ML model (optionnel)
└─ Action      : Améliorer détection spam (rate limiting + patterns)

Solution:

  • Combiner rate limiting + similarité
  • Ajouter détection patterns (URLs répétées, mentions massives)
  • Intégrer ML model (optionnel, TODO ligne 329)

RUST-CHAT-009 | Pas de Redis Pub/Sub

├─ Gravité     : 🟡 P2 - MAJEUR
├─ Description : Broadcast limité à instance unique
├─ Impact      : Pas de scaling horizontal
├─ Effort      : 3-5 jours
├─ Dépendances : Redis présent mais non utilisé
└─ Action      : Implémenter Redis pub/sub pour broadcast multi-instances

Solution:

// Ajouter Redis pub/sub dans broadcast.rs
pub async fn broadcast_to_conversation_redis(
    &self,
    conversation_id: Uuid,
    message: OutgoingMessage,
) -> Result<()> {
    // Publier sur Redis channel
    let channel = format!("conversation:{}", conversation_id);
    let json = serde_json::to_string(&message)?;
    redis_client.publish(channel, json).await?;
    Ok(())
}

RUST-CHAT-010 | Metrics Prometheus Non Utilisées

├─ Gravité     : 🟡 P2 - MAJEUR
├─ Description : Métriques définies mais non enregistrées dans handlers
├─ Impact      : Pas de monitoring production
├─ Effort      : 1 jour
├─ Dépendances : PrometheusMetrics présent
└─ Action      : Enregistrer métriques dans tous les handlers

Solution:

// Ajouter dans WebSocketState
pub metrics: Arc<PrometheusMetrics>,

// Dans handle_incoming_message
state.metrics.record_message_received(content.len() as u64);
let start = Instant::now();
// ... traitement ...
state.metrics.record_message_processing_duration(start.elapsed());

RUST-CHAT-011 | Incohérence Types i32 vs UUID

├─ Gravité     : 🟡 P2 - MAJEUR
├─ Description : read_receipts.rs et moderation.rs utilisent i32 au lieu UUID
├─ Impact      : Incompatibilité avec schéma DB (UUID)
├─ Effort      : 1 jour
├─ Dépendances : Migration DB vers UUID
└─ Action      : Migrer read_receipts et moderation vers UUID

RUST-CHAT-012 | Modules Non Utilisés (Code Mort)

├─ Gravité     : 🟢 P3 - MINEUR
├─ Description : core/ et hub/ présents mais non utilisés
├─ Impact      : Code mort, confusion
├─ Effort      : 2 heures
├─ Dépendances : Aucune
└─ Action      : Supprimer ou intégrer modules

RUST-CHAT-013 | Duplication Auth Modules

├─ Gravité     : 🟢 P3 - MINEUR
├─ Description : auth.rs, authentication.rs, jwt_manager.rs (overlap)
├─ Impact      : Confusion, maintenance difficile
├─ Effort      : 1 jour
├─ Dépendances : Aucune
└─ Action      : Consolider en un seul module auth

RUST-CHAT-014 | Pas de Graceful Shutdown

├─ Gravité     : 🟡 P2 - MAJEUR
├─ Description : Pas de drain connections au shutdown
├─ Impact      : Perte messages en cours, connections brutalement fermées
├─ Effort      : 1 jour
├─ Dépendances : Tokio signal
└─ Action      : Implémenter graceful shutdown avec drain

Solution:

// main.rs
tokio::select! {
    result = axum::serve(listener, app) => { result? },
    _ = tokio::signal::ctrl_c() => {
        info!("🛑 Shutdown signal reçu, drain connections...");
        // Drain WebSocket connections
        ws_manager.drain_all().await;
        info!("✅ Shutdown gracieux terminé");
    }
}

📝 CONCLUSION

Le Chat Server Rust présente une base solide avec:

  • Architecture WebSocket moderne (Axum)
  • Persistence PostgreSQL robuste (SQLx)
  • Structure modulaire claire
  • Features temps-réel partiellement implémentées

Problèmes critiques à résoudre en priorité:

  1. 🔴 Auth WebSocket (token dans URL)
  2. 🔴 Read receipts non implémentés
  3. 🔴 Tests coverage insuffisant
  4. 🟠 Rate limiting non appliqué
  5. 🟠 Validation input manquante

Effort total estimé: 18-27 jours pour atteindre production-ready avec toutes les features ORIGIN_.

Recommandation: Commencer par P0 (3-5 jours), puis P1 (5-7 jours) avant déploiement production.


Fin du rapport d'audit