feat: Release version 3.1.4 - Mode terrain et génération PDF

 Nouvelles fonctionnalités:
- Ajout du mode terrain pour utilisation mobile hors connexion
- Génération automatique de reçus PDF avec template personnalisé
- Révision complète du système de cartes avec amélioration des performances

🔧 Améliorations techniques:
- Refactoring du module chat avec architecture simplifiée
- Optimisation du système de sécurité NIST SP 800-63B
- Amélioration de la gestion des secteurs géographiques
- Support UTF-8 étendu pour les noms d'utilisateurs

📱 Application mobile:
- Nouveau mode terrain dans user_field_mode_page
- Interface utilisateur adaptative pour conditions difficiles
- Synchronisation offline améliorée

🗺️ Cartographie:
- Optimisation des performances MapBox
- Meilleure gestion des tuiles hors ligne
- Amélioration de l'affichage des secteurs

📄 Documentation:
- Ajout guide Android (ANDROID-GUIDE.md)
- Documentation sécurité API (API-SECURITY.md)
- Guide module chat (CHAT_MODULE.md)

🐛 Corrections:
- Résolution des erreurs 400 lors de la création d'utilisateurs
- Correction de la validation des noms d'utilisateurs
- Fix des problèmes de synchronisation chat

🤖 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-19 19:38:03 +02:00
parent 4f7247eb2d
commit 3443277d4a
185 changed files with 109354 additions and 102937 deletions

View File

@@ -0,0 +1,150 @@
#!/usr/bin/env php
<?php
/**
* Script de nettoyage des données de sécurité
* À exécuter via cron quotidiennement
* Exemple crontab: 0 2 * * * /usr/bin/php /var/www/geosector/api/scripts/cron/cleanup_security_data.php
*/
declare(strict_types=1);
// Configuration
require_once __DIR__ . '/../../bootstrap.php';
require_once __DIR__ . '/../../src/Config/AppConfig.php';
require_once __DIR__ . '/../../src/Core/Database.php';
// Initialiser la configuration
$appConfig = AppConfig::getInstance();
$config = $appConfig->getFullConfig();
// Initialiser la base de données
Database::init($config['database']);
$db = Database::getInstance();
// Configuration de rétention (en jours)
$RETENTION_DAYS = [
'performance_metrics' => 30, // Garder 30 jours de métriques
'failed_login_attempts' => 7, // Garder 7 jours de tentatives
'resolved_alerts' => 90, // Garder 90 jours d'alertes résolues
'expired_blocks' => 0 // Débloquer immédiatement les IPs expirées
];
echo "[" . date('Y-m-d H:i:s') . "] Début du nettoyage des données de sécurité\n";
try {
$totalDeleted = 0;
// 1. Nettoyer les métriques de performance
echo "- Nettoyage des métriques de performance (>" . $RETENTION_DAYS['performance_metrics'] . " jours)...\n";
$stmt = $db->prepare('
DELETE FROM sec_performance_metrics
WHERE created_at < DATE_SUB(NOW(), INTERVAL :days DAY)
');
$stmt->execute(['days' => $RETENTION_DAYS['performance_metrics']]);
$deleted = $stmt->rowCount();
echo "$deleted lignes supprimées\n";
$totalDeleted += $deleted;
// 2. Nettoyer les tentatives de login échouées
echo "- Nettoyage des tentatives de login (>" . $RETENTION_DAYS['failed_login_attempts'] . " jours)...\n";
$stmt = $db->prepare('
DELETE FROM sec_failed_login_attempts
WHERE attempt_time < DATE_SUB(NOW(), INTERVAL :days DAY)
');
$stmt->execute(['days' => $RETENTION_DAYS['failed_login_attempts']]);
$deleted = $stmt->rowCount();
echo "$deleted lignes supprimées\n";
$totalDeleted += $deleted;
// 3. Nettoyer les alertes résolues
echo "- Nettoyage des alertes résolues (>" . $RETENTION_DAYS['resolved_alerts'] . " jours)...\n";
$stmt = $db->prepare('
DELETE FROM sec_alerts
WHERE resolved = 1
AND resolved_at < DATE_SUB(NOW(), INTERVAL :days DAY)
');
$stmt->execute(['days' => $RETENTION_DAYS['resolved_alerts']]);
$deleted = $stmt->rowCount();
echo "$deleted lignes supprimées\n";
$totalDeleted += $deleted;
// 4. Débloquer les IPs expirées
echo "- Déblocage des IPs expirées...\n";
$stmt = $db->prepare('
UPDATE sec_blocked_ips
SET unblocked_at = NOW()
WHERE blocked_until <= NOW()
AND unblocked_at IS NULL
AND permanent = 0
');
$stmt->execute();
$unblocked = $stmt->rowCount();
echo "$unblocked IPs débloquées\n";
// 5. Supprimer les anciennes IPs débloquées (optionnel, garder 180 jours d'historique)
echo "- Suppression des anciennes IPs débloquées (>180 jours)...\n";
$stmt = $db->prepare('
DELETE FROM sec_blocked_ips
WHERE unblocked_at IS NOT NULL
AND unblocked_at < DATE_SUB(NOW(), INTERVAL 180 DAY)
');
$stmt->execute();
$deleted = $stmt->rowCount();
echo "$deleted lignes supprimées\n";
$totalDeleted += $deleted;
// 6. Optimiser les tables (optionnel, peut être long sur de grosses tables)
if ($totalDeleted > 1000) {
echo "- Optimisation des tables...\n";
$tables = [
'sec_performance_metrics',
'sec_failed_login_attempts',
'sec_alerts',
'sec_blocked_ips'
];
foreach ($tables as $table) {
try {
$db->exec("OPTIMIZE TABLE $table");
echo " → Table $table optimisée\n";
} catch (Exception $e) {
echo " ⚠ Impossible d'optimiser $table: " . $e->getMessage() . "\n";
}
}
}
// 7. Statistiques finales
echo "\n=== RÉSUMÉ ===\n";
echo "Total supprimé: $totalDeleted lignes\n";
echo "IPs débloquées: $unblocked\n";
// Obtenir les statistiques actuelles
$stats = [];
$tables = [
'sec_alerts' => "SELECT COUNT(*) as total, SUM(resolved = 0) as active FROM sec_alerts",
'sec_performance_metrics' => "SELECT COUNT(*) as total FROM sec_performance_metrics",
'sec_failed_login_attempts' => "SELECT COUNT(*) as total FROM sec_failed_login_attempts",
'sec_blocked_ips' => "SELECT COUNT(*) as total, SUM(permanent = 1) as permanent FROM sec_blocked_ips WHERE unblocked_at IS NULL"
];
echo "\nÉtat actuel des tables:\n";
foreach ($tables as $table => $query) {
$result = $db->query($query)->fetch(PDO::FETCH_ASSOC);
if ($table === 'sec_alerts') {
echo "- $table: {$result['total']} total, {$result['active']} actives\n";
} elseif ($table === 'sec_blocked_ips') {
$permanent = $result['permanent'] ?? 0;
echo "- $table: {$result['total']} bloquées, $permanent permanentes\n";
} else {
echo "- $table: {$result['total']} enregistrements\n";
}
}
echo "\n[" . date('Y-m-d H:i:s') . "] Nettoyage terminé avec succès\n";
} catch (Exception $e) {
echo "\n❌ ERREUR: " . $e->getMessage() . "\n";
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
exit(1);
}