mirror of
https://github.com/R0m1k3/xtremobile.git
synced 2026-10-11 17:29:26 +02:00
Phase 2: Performance Profiling Setup - Add profiling utilities
- Add StartupProfiler: Measure cold/warm start times - Add VideoProfiler: Profile video load, playback metrics - Add MemoryProfiler: Detect memory leaks, monitor heap growth - Add HiveEncryptionBenchmark: Measure encryption overhead - Add PHASE_2_PROFILING_PLAN.md: Complete testing procedures Ready for profiling execution once Flutter SDK is initialized
This commit is contained in:
1 parent
1293a159ee
commit
c5fcafcce1
553 files changed
+85219
No files matched your search
@@ -0,0 +1,519 @@
|
||||
# 🐛 LISTE DES PROBLÈMES DÉTECTÉS ET SOLUTIONS
|
||||
|
||||
## BACKEND (Dart Server)
|
||||
|
||||
### 🔴 CRITIQUE
|
||||
|
||||
#### 1. **Password Hashing Basique (SHA-256 simple)**
|
||||
**Fichier**: `bin/utils/password_hasher.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
static String hash(String password) {
|
||||
final bytes = utf8.encode(password);
|
||||
return sha256.convert(bytes).toString();
|
||||
}
|
||||
```
|
||||
- ❌ Pas de salt aléatoire
|
||||
- ❌ Facile à cracker (lookup tables)
|
||||
- ❌ Non conforme OWASP
|
||||
|
||||
**Solution**: Remplacer par bcrypt (cf. IMPLEMENTATION_GUIDE.md Section 3.2)
|
||||
|
||||
---
|
||||
|
||||
#### 2. **Pas de Logging Structuré**
|
||||
**Fichier**: Partout où il y a `print()`
|
||||
**Problème**:
|
||||
- ❌ Impossible de persister les logs
|
||||
- ❌ Pas de nivaux de sévérité
|
||||
- ❌ Pas de traçage end-to-end
|
||||
- ❌ Impossible de debugger en production
|
||||
|
||||
**Solution**: Implémenter LoggingService (cf. IMPLEMENTATION_GUIDE.md Section 1.2)
|
||||
|
||||
---
|
||||
|
||||
#### 3. **Gestion d'Erreurs Incohérente**
|
||||
**Fichier**: `bin/api/*.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
// Incohérent:
|
||||
return Response(401, body: jsonEncode({'success': false, 'error': 'Invalid credentials'}));
|
||||
return Response.internalServerError(body: ...);
|
||||
throw Exception(e); // Crash
|
||||
```
|
||||
|
||||
**Solution**: Exceptions unifiées (cf. IMPLEMENTATION_GUIDE.md Section 2)
|
||||
|
||||
---
|
||||
|
||||
#### 4. **Tokens sans Expiration**
|
||||
**Fichier**: `bin/models/session.dart`
|
||||
**Problème**:
|
||||
- ❌ Sessions vivre éternellement
|
||||
- ❌ Pas de refresh token
|
||||
- ❌ Impossible de révoquer à distance
|
||||
|
||||
**Solution**: JWT + refresh tokens (cf. IMPLEMENTATION_GUIDE.md Section 3.3)
|
||||
|
||||
---
|
||||
|
||||
#### 5. **SQL Injection Peu Probable mais Risquée**
|
||||
**Fichier**: `bin/database/database.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
_db.select('SELECT * FROM users WHERE username = ?', [username]); // OK
|
||||
_db.execute('''CREATE TABLE IF NOT EXISTS users (...)'''); // Hardcoded OK
|
||||
```
|
||||
- ⚠️ Utilise les paramètres (bon!)
|
||||
- ❌ Mais pas de validation input
|
||||
|
||||
**Solution**: Ajouter validation Schema dans chaque handler
|
||||
|
||||
---
|
||||
|
||||
### 🟠 IMPORTANT
|
||||
|
||||
#### 6. **Pas de Backup Automatique**
|
||||
**Fichier**: Manquant
|
||||
**Problème**:
|
||||
- ❌ Si DB corrompue, données perdues
|
||||
- ❌ Pas de disaster recovery
|
||||
|
||||
**Solution**: BackupService (cf. IMPLEMENTATION_GUIDE.md Section 4.2)
|
||||
|
||||
---
|
||||
|
||||
#### 7. **Pas de Migrations Database**
|
||||
**Fichier**: `bin/database/database.dart`
|
||||
**Problème**:
|
||||
- ❌ Impossible d'updater schema en production
|
||||
- ❌ Versionning unclear
|
||||
- ❌ Risque de corruption
|
||||
|
||||
**Solution**: Migration system (cf. IMPLEMENTATION_GUIDE.md Section 4.1)
|
||||
|
||||
---
|
||||
|
||||
#### 8. **Rate Limiting Limité**
|
||||
**Fichier**: `bin/middleware/security_middleware.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
Middleware rateLimitMiddleware({int requestsPerMinute = 200}) {
|
||||
// Par IP, OK
|
||||
// Mais:
|
||||
// - Pas spécifique par endpoint
|
||||
// - Pas de persistent storage (reset au redémarrage)
|
||||
// - Pas de 2FA rate limiting dur
|
||||
}
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
- Rate limiting par endpoint: `/api/auth/login` (5/5min)
|
||||
- Lockout temporaire: après 5 tentatives
|
||||
- Persistent storage (Redis ou DB)
|
||||
|
||||
---
|
||||
|
||||
#### 9. **Secrets en Clair**
|
||||
**Fichier**: `.env` (n'existe pas)
|
||||
**Problème**:
|
||||
- ❌ JWT_SECRET hardcoded
|
||||
- ❌ Database path hardcoded
|
||||
- ❌ Credentials Xtream côté client
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# .env.example (ne pas commit .env)
|
||||
JWT_SECRET=your-secret-here
|
||||
DATABASE_PATH=/app/data/xtremflow.db
|
||||
NODE_ENV=production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 10. **FFmpeg Process Management**
|
||||
**Fichier**: `bin/server.dart` (fonction `_createStreamHandler`)
|
||||
**Problème**:
|
||||
```dart
|
||||
// Bon:
|
||||
controller.onCancel = () {
|
||||
print('Client disconnected for $streamId. Killing FFmpeg...');
|
||||
process.kill();
|
||||
};
|
||||
|
||||
// Mais:
|
||||
// - Pas de timeout FFmpeg (si hang)
|
||||
// - Pas de memory limit
|
||||
// - Pas de détection process crash
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
// Timeout pour procédure longue
|
||||
final timeout = Future.delayed(const Duration(seconds: 120), () {
|
||||
if (process.isRunning) {
|
||||
process.kill();
|
||||
logger.logError('FFmpeg timeout for $streamId', null, null);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟡 AMÉLIORATION
|
||||
|
||||
#### 11. **Pas de Tests Unitaires Backend**
|
||||
**Fichier**: `test/` (vide ou minimal)
|
||||
**Problème**:
|
||||
- ❌ Risque de régression
|
||||
- ❌ Impossible de refactorer confiantément
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
// test/unit/auth_test.dart
|
||||
void main() {
|
||||
group('API Auth', () {
|
||||
test('login success', () { ... });
|
||||
test('login invalid credentials', () { ... });
|
||||
test('token refresh', () { ... });
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 12. **Pas de Documentation API**
|
||||
**Fichier**: Manquant (ni OpenAPI, ni Postman)
|
||||
**Problème**:
|
||||
- ❌ Frontend et backend se désynchronisent
|
||||
- ❌ Onboarding difficile
|
||||
|
||||
**Solution**: Générer OpenAPI depuis code avec `shelf_openapi`
|
||||
|
||||
---
|
||||
|
||||
## FRONTEND (Flutter)
|
||||
|
||||
### 🔴 CRITIQUE
|
||||
|
||||
#### 13. **Pas de Gestion d'Erreurs Centralisée**
|
||||
**Fichier**: `lib/core/api/api_client.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
Future<Response> get(String path) async {
|
||||
return _dio.get(path); // Exception directe au caller
|
||||
}
|
||||
// Chaque écran doit gérer les erreurs
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
Future<T> get<T>(String path, T Function(Map) parser) async {
|
||||
try {
|
||||
final response = await _dio.get(path);
|
||||
return parser(jsonDecode(response.data));
|
||||
} on DioException catch (e) {
|
||||
throw NetworkException(
|
||||
message: e.message ?? 'Network error',
|
||||
code: 'NETWORK_ERROR',
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 14. **TODO non résolus**
|
||||
**Fichier**: `lib/core/api/api_client.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
String _getBaseUrl() {
|
||||
// TODO: Configure base URL for mobile
|
||||
return '';
|
||||
}
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
String _getBaseUrl() {
|
||||
const isProd = String.fromEnvironment('ENV') == 'production';
|
||||
return isProd
|
||||
? 'https://api.example.com'
|
||||
: 'http://localhost:8089';
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 15. **Pas d'Encryption Données Locales**
|
||||
**Fichier**: `lib/core/database/hive_service.dart`
|
||||
**Problème**:
|
||||
- ❌ Hive stocke auth_token en clair
|
||||
- ❌ Credentials playlist en clair
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
// Ajouter chiffrement Hive
|
||||
await Hive.openBox(
|
||||
'secure_box',
|
||||
encryptionCipher: HiveAesCipher(secretKey),
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 16. **Riverpod Providers Pas Optimisés**
|
||||
**Fichier**: `lib/features/iptv/providers/`
|
||||
**Problème**:
|
||||
- ❌ Pas de `family` modifiers pour paramètres
|
||||
- ❌ Pas de `select` pour optimiser re-renders
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
final playlistProvider = FutureProvider.family<Playlist, String>(
|
||||
(ref, playlistId) {
|
||||
final api = ref.watch(apiClientProvider);
|
||||
return api.getPlaylist(playlistId);
|
||||
},
|
||||
);
|
||||
|
||||
// Utilisation
|
||||
final playlist = ref.watch(playlistProvider(selectedId));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟠 IMPORTANT
|
||||
|
||||
#### 17. **Gestion Cache Implicite**
|
||||
**Fichier**: `lib/core/api/api_client.dart`
|
||||
**Problème**:
|
||||
- ❌ Caching via Dio couche basse
|
||||
- ❌ Pas de contrôle granulaire (TTL par endpoint)
|
||||
- ❌ UI ne sait pas quand les données sont en cache
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
final cachedPlaylistsProvider = FutureProvider<List<Playlist>>(
|
||||
(ref) async {
|
||||
final api = ref.watch(apiClientProvider);
|
||||
// Cache 5 min automatiquement via Riverpod
|
||||
final ref.keepAlive(); // Garder en memory
|
||||
return api.getPlaylists();
|
||||
},
|
||||
).withCache(const Duration(minutes: 5));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 18. **Pas de Gestion Hors-Ligne**
|
||||
**Fichier**: N/A
|
||||
**Problème**:
|
||||
- ❌ Si serveur down, app crash
|
||||
- ❌ Pas de cached data fallback
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
FutureProvider avec fallback:
|
||||
- Récupérer depuis API
|
||||
- Si fail, chercher dans cache local Hive
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 19. **Navigation Manuelle (go_router pas optimisé)**
|
||||
**Fichier**: `lib/core/router/app_router.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
if (MediaQuery.of(context).size.width < 768) {
|
||||
return MobileLoginScreen();
|
||||
}
|
||||
return LoginScreen();
|
||||
// Duplication pour chaque route
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
// Créer builder factory:
|
||||
Widget _buildPageForForm(
|
||||
BuildContext ctx,
|
||||
Widget mobileScreen,
|
||||
Widget desktopScreen,
|
||||
) {
|
||||
return MediaQuery.of(ctx).size.width < 768 ? mobileScreen : desktopScreen;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 20. **Manque Tests UI**
|
||||
**Fichier**: `test/widget_test.dart`
|
||||
**Problème**:
|
||||
- ❌ Seul 1 test existant
|
||||
- ❌ Pas de couverture features
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
// test/widget/login_screen_test.dart
|
||||
void main() {
|
||||
testWidgets('Login screen displays username field', (WidgetTester tester) {
|
||||
await tester.pumpWidget(const MyApp());
|
||||
expect(find.byType(TextField), findsWidgets);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DEVOPS & DEPLOYMENT
|
||||
|
||||
### 🟡 AMÉLIORATION
|
||||
|
||||
#### 21. **Docker Image Pas Optimisée**
|
||||
**Fichier**: `Dockerfile`
|
||||
**Problème**:
|
||||
- ❌ Pas de multi-stage build
|
||||
- ❌ Couches non optimisées
|
||||
- ❌ Taille image potentiellement large
|
||||
|
||||
**Solution**:
|
||||
```dockerfile
|
||||
# Stage 1: Build
|
||||
FROM google/dart:latest AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN dart pub get && dart compile exe server.dart -o server
|
||||
|
||||
# Stage 2: Runtime
|
||||
FROM debian:bookworm-slim
|
||||
COPY --from=builder /app/server /app/server
|
||||
CMD ["./server"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 22. **Pas de Healthcheck**
|
||||
**Fichier**: `docker-compose.yml`
|
||||
**Problème**:
|
||||
- ❌ Docker ne sait pas si app est healthy
|
||||
- ❌ Redémarrage automatique pas fiable
|
||||
|
||||
**Solution**:
|
||||
```dockerfile
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8089/api/health || exit 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 23. **Pas de CI/CD Pipeline**
|
||||
**Fichier**: `.github/workflows/` (N/A)
|
||||
**Problème**:
|
||||
- ❌ Tests manuels
|
||||
- ❌ Déploiement manuel risqué
|
||||
- ❌ Pas de vérification qualité
|
||||
|
||||
**Solution**: Créer GitHub Actions (test, lint, build, deploy)
|
||||
|
||||
---
|
||||
|
||||
## SÉCURITÉ GÉNÉRALE
|
||||
|
||||
### 🔴 CRITIQUE
|
||||
|
||||
#### 24. **CORS Permissif**
|
||||
**Fichier**: `bin/server.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
Middleware _corsMiddleware() {
|
||||
return (Handler handler) {
|
||||
return (Request request) async {
|
||||
final response = await handler(request);
|
||||
return response.change(headers: {
|
||||
'Access-Control-Allow-Origin': '*', // ❌ DANGEREUX!
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
'Access-Control-Allow-Origin': 'https://example.com',
|
||||
// Ou lire depuis config:
|
||||
final origin = request.headers['origin'];
|
||||
if (_allowedOrigins.contains(origin)) {
|
||||
// Add header
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 25. **Pas de CSRF Protection**
|
||||
**Fichier**: N/A
|
||||
**Problème**:
|
||||
- ❌ Requête forgée possible depuis autre site
|
||||
- ❌ Utilisateur clique lien malveillant → action without consent
|
||||
|
||||
**Solution**: Token CSRF unique par session
|
||||
|
||||
---
|
||||
|
||||
#### 26. **Pas de Validation Input Stricte**
|
||||
**Fichier**: `bin/api/*.dart`
|
||||
**Problème**:
|
||||
```dart
|
||||
final username = payload['username'] as String?; // Pas de validation!
|
||||
// Accepte "", " ", très long, etc.
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```dart
|
||||
class ValidationException extends AppException { ... }
|
||||
|
||||
if (username == null || username.isEmpty || username.length > 50) {
|
||||
throw ValidationException(
|
||||
message: 'Username must be 1-50 characters',
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 RÉSUMÉ PROBLÈMES PAR SÉVÉRITÉ
|
||||
|
||||
| Sévérité | Count | Examples |
|
||||
|----------|-------|----------|
|
||||
| 🔴 Critique | 11 | Password hashing, logging, errors, tokens, CORS |
|
||||
| 🟠 Important | 9 | Backup, migrations, rate limiting, encryption |
|
||||
| 🟡 Amélioration | 6 | Tests, docs, Docker, CI/CD |
|
||||
| **Total** | **26** | |
|
||||
|
||||
---
|
||||
|
||||
## 📈 IMPACT ESTIMATION
|
||||
|
||||
| Problème | Impact | Fix Time | Business Value |
|
||||
|----------|--------|----------|-----------------|
|
||||
| 1. Password | 🔴 Critique | 0.5j | 🟢 Très haut |
|
||||
| 2. Logging | 🔴 Critique | 1j | 🟢 Très haut |
|
||||
| 3. Errors | 🔴 Critique | 1j | 🟢 Très haut |
|
||||
| 4. Tokens | 🔴 Critique | 2j | 🟢 Très haut |
|
||||
| 6. Backup | 🟠 Important | 1j | 🟡 Haut |
|
||||
|
||||
---
|
||||
|
||||
## ✅ QUICK WINS (Fix en < 1 jour)
|
||||
|
||||
1. Ajouter logger package
|
||||
2. Remplacer print() critiques par logging
|
||||
3. Ajouter CORS origin check
|
||||
4. Ajouter validation input basique
|
||||
5. Ajouter .env secrets
|
||||
|
||||
---
|
||||
|
||||
*Document généré: 25 Mars 2026*
|
||||
*Dernière maj: Jour 1*
|
||||
Reference in new issue
Block a user