credit-direct/app/libraries/TurnstileValidator.php
2025-12-18 09:44:42 +01:00

185 lines
6.3 KiB
PHP

<?php
namespace libraries;
/**
* Classe de validation Cloudflare Turnstile
*/
class TurnstileValidator
{
private $secretKey;
private $timeout;
/**
* Constructeur
* @param string $secretKey Clé secrète Turnstile (optionnel, utilise la constante par défaut)
* @param int $timeout Timeout en millisecondes (optionnel, défaut 10000ms)
*/
public function __construct($secretKey = null, $timeout = 10000)
{
$this->secretKey = $secretKey ?: _CRED_TURNSTILE_SECRET_KEY_;
$this->timeout = $timeout;
}
/**
* Valide un token Turnstile
*
* @param string $token Le token à valider
* @param string $remoteip L'adresse IP du client (optionnel)
* @param string $idempotencyKey Clé d'idempotence pour éviter les doublons (optionnel)
* @return array Résultat de la validation
*/
public function validate($token, $remoteip = null, $idempotencyKey = null)
{
// Validation des paramètres d'entrée
if (empty($token) || !is_string($token)) {
return [
'success' => false,
'error' => 'Token manquant ou invalide',
'error_codes' => ['missing-input-response']
];
}
if (strlen($token) > 2048) {
return [
'success' => false,
'error' => 'Token trop long',
'error_codes' => ['invalid-input-response']
];
}
// Préparation de la requête
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$postData = [
'secret' => $this->secretKey,
'response' => $token
];
if (!empty($remoteip)) {
$postData['remoteip'] = $remoteip;
}
if (!empty($idempotencyKey)) {
$postData['idempotency_key'] = $idempotencyKey;
}
// Configuration cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->timeout);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
// Exécution de la requête
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// Gestion des erreurs cURL
if ($response === false) {
error_log('Turnstile validation cURL error: ' . $curlError);
return [
'success' => false,
'error' => 'Erreur de connexion au service Turnstile',
'error_codes' => ['internal-error']
];
}
// Vérification du code HTTP
if ($httpCode !== 200) {
error_log('Turnstile validation HTTP error: ' . $httpCode);
return [
'success' => false,
'error' => 'Erreur du service Turnstile (HTTP ' . $httpCode . ')',
'error_codes' => ['internal-error']
];
}
// Décodage de la réponse JSON
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('Turnstile validation JSON decode error: ' . json_last_error_msg());
return [
'success' => false,
'error' => 'Erreur de parsing de la réponse Turnstile',
'error_codes' => ['internal-error']
];
}
// Validation du succès
if (!isset($result['success'])) {
error_log('Turnstile validation missing success field in response');
return [
'success' => false,
'error' => 'Réponse invalide du service Turnstile',
'error_codes' => ['internal-error']
];
}
return $result;
}
/**
* Valide un token avec gestion d'erreurs formatée pour l'affichage
*
* @param string $token Le token à valider
* @param string $remoteip L'adresse IP du client (optionnel)
* @return array Résultat formaté pour l'affichage
*/
public function validateForDisplay($token, $remoteip = null)
{
$result = $this->validate($token, $remoteip);
if ($result['success']) {
return [
'valid' => true,
'message' => '',
'data' => $result
];
}
// Mapping des erreurs pour l'affichage utilisateur
$errorMessages = [
'missing-input-secret' => 'Configuration Turnstile invalide.',
'invalid-input-secret' => 'Configuration Turnstile invalide.',
'missing-input-response' => 'Vérification de sécurité manquante. Veuillez cocher la case "Je ne suis pas un robot".',
'invalid-input-response' => 'Vérification de sécurité invalide. Veuillez réessayer.',
'bad-request' => 'Requête de vérification invalide.',
'timeout-or-duplicate' => 'Vérification de sécurité expirée. Veuillez réessayer.',
'internal-error' => 'Erreur temporaire du service de sécurité. Veuillez réessayer dans quelques instants.'
];
$errorCodes = isset($result['error-codes']) ? $result['error-codes'] : ['internal-error'];
$errorCode = reset($errorCodes); // Premier code d'erreur
$message = isset($errorMessages[$errorCode]) ? $errorMessages[$errorCode] : 'Erreur de vérification de sécurité inconnue.';
return [
'valid' => false,
'message' => $message,
'error_codes' => $errorCodes,
'data' => $result
];
}
/**
* Vérifie si Turnstile est correctement configuré
*
* @return bool True si configuré, false sinon
*/
public static function isConfigured()
{
return defined('_CRED_TURNSTILE_SECRET_KEY_') &&
_CRED_TURNSTILE_SECRET_KEY_ !== '' &&
_CRED_TURNSTILE_SECRET_KEY_ !== 'YOUR_SECRET_KEY_HERE' &&
defined('_CRED_TURNSTILE_SITE_KEY_') &&
_CRED_TURNSTILE_SITE_KEY_ !== '' &&
_CRED_TURNSTILE_SITE_KEY_ !== 'YOUR_SITE_KEY_HERE';
}
}