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

1019 lines
32 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔍 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**