veza/veza-chat-server/AUDIT_CHAT_SERVER_RUST.md

1020 lines
32 KiB
Markdown
Raw Normal View History

2025-12-03 19:33:26 +00:00
# 🔍 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<WebSocketClient>>)
- 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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<WebSocketClient>> 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**:
```rust
// 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**:
```rust
// 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**:
```bash
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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**:
```rust
// 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**