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

188
bao/lib/CryptoService.php Normal file
View File

@@ -0,0 +1,188 @@
<?php
declare(strict_types=1);
/**
* Service de chiffrement/déchiffrement AES-256-CBC
* Compatible avec le système de chiffrement de l'API Geosector
*/
class CryptoService {
private string $encryptionKey;
private string $cipher = 'AES-256-CBC';
public function __construct(string $encryptionKey) {
// Décoder la clé base64
$this->encryptionKey = base64_decode($encryptionKey);
if (strlen($this->encryptionKey) !== 32) {
throw new RuntimeException("La clé de chiffrement doit faire 32 bytes (256 bits)");
}
}
/**
* Déchiffre les données "searchable" (encrypted_user_name, encrypted_email)
* Format: base64 simple avec IV fixe
*/
public function decryptSearchable(?string $encryptedData): ?string {
if (empty($encryptedData)) {
return null;
}
$encrypted = base64_decode($encryptedData);
if ($encrypted === false) {
return null;
}
$iv = str_repeat("\0", 16); // IV fixe
$decrypted = openssl_decrypt($encrypted, $this->cipher, $this->encryptionKey, 0, $iv);
if ($decrypted === false) {
return null;
}
// Supprimer le caractère de contrôle ajouté
if (substr($decrypted, -1) === "\x01") {
return substr($decrypted, 0, -1);
}
return $decrypted;
}
/**
* Déchiffre les données avec IV aléatoire (encrypted_name, encrypted_phone, etc.)
* Format: base64(IV + encrypted)
*/
public function decryptWithIV(?string $encryptedData): ?string {
if (empty($encryptedData)) {
return null;
}
$data = base64_decode($encryptedData);
if ($data === false) {
return null;
}
$ivLength = openssl_cipher_iv_length($this->cipher);
if (strlen($data) <= $ivLength) {
return null;
}
$iv = substr($data, 0, $ivLength);
$encrypted = substr($data, $ivLength);
$decrypted = openssl_decrypt($encrypted, $this->cipher, $this->encryptionKey, 0, $iv);
return $decrypted !== false ? $decrypted : null;
}
/**
* Déchiffre une valeur chiffrée
*
* @param string|null $encryptedValue Valeur chiffrée (format base64:iv:data)
* @return string|null Valeur déchiffrée ou null
*/
public function decrypt(?string $encryptedValue): ?string {
if (empty($encryptedValue)) {
return null;
}
// Le format de l'API est : base64:iv:encrypted_data
$parts = explode(':', $encryptedValue);
if (count($parts) !== 3 || $parts[0] !== 'base64') {
// Format invalide, peut-être déjà en clair
return $encryptedValue;
}
$iv = base64_decode($parts[1]);
$encrypted = base64_decode($parts[2]);
if ($iv === false || $encrypted === false) {
throw new RuntimeException("Impossible de décoder les données chiffrées");
}
$decrypted = openssl_decrypt(
$encrypted,
$this->cipher,
$this->encryptionKey,
OPENSSL_RAW_DATA,
$iv
);
if ($decrypted === false) {
throw new RuntimeException("Échec du déchiffrement : " . openssl_error_string());
}
return $decrypted;
}
/**
* Chiffre une valeur
*
* @param string $value Valeur à chiffrer
* @return string Valeur chiffrée (format base64:iv:data)
*/
public function encrypt(string $value): string {
$ivLength = openssl_cipher_iv_length($this->cipher);
$iv = openssl_random_pseudo_bytes($ivLength);
$encrypted = openssl_encrypt(
$value,
$this->cipher,
$this->encryptionKey,
OPENSSL_RAW_DATA,
$iv
);
if ($encrypted === false) {
throw new RuntimeException("Échec du chiffrement : " . openssl_error_string());
}
return 'base64:' . base64_encode($iv) . ':' . base64_encode($encrypted);
}
/**
* Déchiffre plusieurs colonnes d'un tableau
*
* @param array $row Ligne de base de données
* @param array $encryptedColumns Liste des colonnes à déchiffrer (sans le préfixe encrypted_)
* @return array Tableau avec colonnes déchiffrées
*/
public function decryptRow(array $row, array $encryptedColumns): array {
$decrypted = $row;
foreach ($encryptedColumns as $column) {
$encryptedColumn = 'encrypted_' . $column;
if (isset($row[$encryptedColumn])) {
$decrypted[$column] = $this->decrypt($row[$encryptedColumn]);
}
}
return $decrypted;
}
/**
* Déchiffre les colonnes encrypted_* d'un utilisateur
*
* @param array $user Données utilisateur
* @return array Utilisateur avec données déchiffrées
*/
public function decryptUser(array $user): array {
$columns = ['user_name', 'email', 'name', 'phone', 'mobile'];
return $this->decryptRow($user, $columns);
}
/**
* Déchiffre les colonnes encrypted_* d'une entité
*
* @param array $entite Données entité
* @return array Entité avec données déchiffrées
*/
public function decryptEntite(array $entite): array {
$columns = ['name', 'email', 'phone', 'mobile', 'iban', 'bic'];
return $this->decryptRow($entite, $columns);
}
}