feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API

- Mise à jour VERSION vers 3.3.4
- Optimisations et révisions architecture API (deploy-api.sh, scripts de migration)
- Ajout documentation Stripe Tap to Pay complète
- Migration vers polices Inter Variable pour Flutter
- Optimisations build Android et nettoyage fichiers temporaires
- Amélioration système de déploiement avec gestion backups
- Ajout scripts CRON et migrations base de données

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-10-05 20:11:15 +02:00
parent 2786252307
commit 570a1fa1f0
212 changed files with 24275 additions and 11321 deletions

174
bao/bin/reset-password Executable file
View File

@@ -0,0 +1,174 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* Script de réinitialisation du mot de passe d'un utilisateur
* Génère un nouveau mot de passe sécurisé et l'enregistre
* Usage: ./reset-password <environment> <user_id>
*/
require_once __DIR__ . '/../lib/CryptoService.php';
require_once __DIR__ . '/../lib/DatabaseConnection.php';
require_once __DIR__ . '/../lib/helpers.php';
// Vérifier les arguments
if ($argc < 3) {
error("Usage: " . basename($argv[0]) . " <environment> <user_id>");
error("Exemple: " . basename($argv[0]) . " dev 123");
exit(1);
}
$environment = strtoupper($argv[1]);
$userId = (int)$argv[2];
/**
* Génère un mot de passe sécurisé selon les règles de l'API
* Règles conformes à PasswordSecurityService de l'API
*
* @param int $length Longueur du mot de passe (12-20)
* @return string Mot de passe généré
*/
function generateSecurePassword(int $length = 14): string {
// Limiter la longueur entre 12 et 20 (règles API)
$length = max(12, min(20, $length));
// Caractères autorisés (sans ambiguïté visuelle - règles API)
$lowercase = 'abcdefghijkmnopqrstuvwxyz'; // sans l
$uppercase = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // sans I, O
$numbers = '23456789'; // sans 0, 1
$special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
$password = '';
// Garantir au moins un caractère de chaque type (règle API)
$password .= $lowercase[random_int(0, strlen($lowercase) - 1)];
$password .= $uppercase[random_int(0, strlen($uppercase) - 1)];
$password .= $numbers[random_int(0, strlen($numbers) - 1)];
$password .= $special[random_int(0, strlen($special) - 1)];
// Compléter avec des caractères aléatoires
$allChars = $lowercase . $uppercase . $numbers . $special;
for ($i = strlen($password); $i < $length; $i++) {
$password .= $allChars[random_int(0, strlen($allChars) - 1)];
}
// Mélanger les caractères (règle API)
$passwordArray = str_split($password);
shuffle($passwordArray);
return implode('', $passwordArray);
}
try {
// Ouvrir le tunnel SSH si nécessaire
$tunnelScript = __DIR__ . '/_ssh-tunnel.sh';
exec("$tunnelScript open $environment 2>&1", $output, $exitCode);
if ($exitCode !== 0) {
error("Impossible d'ouvrir le tunnel SSH");
exit(1);
}
// Connexion à la base de données
$db = new DatabaseConnection($environment);
$pdo = $db->connect();
info("Environnement: $environment");
info("Recherche de l'utilisateur #$userId...\n");
// Vérifier que l'utilisateur existe
$stmt = $pdo->prepare("
SELECT
u.id,
u.encrypted_user_name,
u.encrypted_email,
u.encrypted_name,
u.first_name
FROM users u
WHERE u.id = :user_id
");
$stmt->execute(['user_id' => $userId]);
$user = $stmt->fetch();
if (!$user) {
error("Utilisateur #$userId introuvable");
exit(1);
}
// Déchiffrer les données pour affichage
$config = DatabaseConfig::getInstance();
$crypto = new CryptoService($config->getEncryptionKey());
$userName = $crypto->decryptSearchable($user['encrypted_user_name']);
$email = $crypto->decryptSearchable($user['encrypted_email']);
$name = $crypto->decryptWithIV($user['encrypted_name']);
$firstName = $user['first_name'];
// Afficher les infos utilisateur
title("RÉINITIALISATION DU MOT DE PASSE");
echo color("Utilisateur\n", 'bold');
display("ID", (string)$user['id']);
display("Username", $userName);
display("Prénom", $firstName);
display("Nom", $name);
display("Email", $email);
echo "\n";
// Demander confirmation
if (!confirm("Confirmer la réinitialisation du mot de passe ?")) {
warning("Opération annulée");
exit(0);
}
// Générer un nouveau mot de passe
$newPassword = generateSecurePassword(14);
$passwordHash = password_hash($newPassword, PASSWORD_BCRYPT);
info("\nGénération du nouveau mot de passe...");
// Mettre à jour la base de données
$updateStmt = $pdo->prepare("
UPDATE users
SET user_pass_hash = :password_hash,
updated_at = CURRENT_TIMESTAMP
WHERE id = :user_id
");
$updateStmt->execute([
'password_hash' => $passwordHash,
'user_id' => $userId
]);
if ($updateStmt->rowCount() === 0) {
error("Erreur lors de la mise à jour du mot de passe");
exit(1);
}
// Afficher le résultat
echo "\n";
success("Mot de passe réinitialisé avec succès !");
echo "\n";
echo color("═══════════════════════════════════════════\n", 'cyan');
echo color(" NOUVEAU MOT DE PASSE\n", 'bold');
echo color("═══════════════════════════════════════════\n", 'cyan');
echo "\n";
echo color(" ", 'green') . color($newPassword, 'yellow') . "\n";
echo "\n";
echo color("═══════════════════════════════════════════\n", 'cyan');
echo "\n";
warning("⚠ Conservez ce mot de passe en lieu sûr !");
warning(" Il ne sera pas possible de le récupérer.");
echo "\n";
} catch (Exception $e) {
error("Erreur: " . $e->getMessage());
exit(1);
}