468 lines
17 KiB
PHP
468 lines
17 KiB
PHP
<?php
|
||
session_start();
|
||
|
||
// Ajout des logs Discord (chemin via __DIR__ car captcha.php est à la racine du site)
|
||
require_once(__DIR__ . '/functions/sendLogs.php');
|
||
|
||
// Recharger une nouvelle série si demandé
|
||
if (isset($_GET['reload']) && $_GET['reload'] === '1') {
|
||
unset($_SESSION['captcha_round']);
|
||
header('Location: ./captcha.php');
|
||
exit;
|
||
}
|
||
|
||
// Si le captcha est déjà validé, rediriger vers l'accueil
|
||
if (isset($_SESSION['captcha_valid']) && $_SESSION['captcha_valid'] === true) {
|
||
header('Location: ./index.php');
|
||
exit;
|
||
}
|
||
|
||
// Nombre maximum d'essais
|
||
$maxAttempts = 3;
|
||
|
||
// Liste des sujets normaux
|
||
$normalSubjects = [
|
||
'Votre rendez-vous est confirmé',
|
||
'Photo de famille',
|
||
'Invitation à déjeuner',
|
||
'Votre facture est disponible',
|
||
'Message de votre médecin',
|
||
'Votre colis arrivera demain',
|
||
'Reçu de paiement',
|
||
'Informations sur votre abonnement',
|
||
'Rappel de rendez-vous',
|
||
'Bulletin d’information',
|
||
'Horaire modifié',
|
||
'Demande de nouvelles',
|
||
'Anniversaire ce week-end',
|
||
'Confirmation de réservation',
|
||
'Mise à jour de votre compte',
|
||
'Message du voisin',
|
||
'Résultats d’analyse disponibles',
|
||
'Programme de la semaine',
|
||
'Votre commande a bien été envoyée',
|
||
'Merci pour votre visite',
|
||
'Document joint',
|
||
'Nouvelles de la famille',
|
||
'Convocation à la réunion',
|
||
'Changement d’horaire',
|
||
'Votre facture d’eau',
|
||
'Votre relevé est prêt',
|
||
'Confirmation de présence',
|
||
'Infos importantes pour demain',
|
||
'Rappel amical',
|
||
'Livraison prévue aujourd’hui',
|
||
'Votre réservation est confirmée',
|
||
'Message de la mairie',
|
||
'Avis de passage',
|
||
'Votre ticket est traité',
|
||
'Mise à jour de votre dossier',
|
||
'Message de l’école',
|
||
'Facture mensuelle',
|
||
'Invitation à la réunion',
|
||
'Confirmation de paiement',
|
||
'Votre commande est en route',
|
||
'Rappel de consultation',
|
||
'Nouvelle réponse reçue',
|
||
'Votre dossier a été mis à jour',
|
||
'Planning de la semaine',
|
||
'Reçu de réservation',
|
||
'Informations utiles',
|
||
'Votre assurance vous écrit',
|
||
'Message de votre pharmacien',
|
||
'Document disponible en ligne',
|
||
'Petit rappel important',
|
||
'Votre livraison est confirmée',
|
||
'Message du service client',
|
||
'Votre demande a été reçue',
|
||
'Lettre d’information',
|
||
'Nouvelles du jour',
|
||
'Confirmation de votre présence',
|
||
'Votre justificatif est prêt',
|
||
'Reçu de transaction',
|
||
'Votre compte a été mis à jour',
|
||
'Avis d’information',
|
||
'Votre dossier avance',
|
||
'Information concernant votre contrat',
|
||
'Message de votre banque',
|
||
'Votre échéance approche',
|
||
'Réponse à votre demande',
|
||
'Merci pour votre confiance',
|
||
'Votre pharmacie vous informe',
|
||
'Rappel de paiement',
|
||
'Votre colis a quitté l’entrepôt',
|
||
'Votre abonnement continue',
|
||
'Message de votre mutuelle',
|
||
'Invitation familiale',
|
||
'Nouveau message reçu',
|
||
'Votre place est réservée',
|
||
'Votre facture du mois',
|
||
'Compte-rendu envoyé',
|
||
'Votre demande est en cours',
|
||
'Rappel pour demain',
|
||
'Réception confirmée',
|
||
'Votre transport est réservé',
|
||
'Bonne réception',
|
||
'Votre document est validé',
|
||
'Votre suivi est disponible',
|
||
'Petit message amical',
|
||
'Confirmation de livraison',
|
||
'Votre note est disponible',
|
||
'Mise à jour d’informations',
|
||
'Votre service est activé',
|
||
'Votre message a bien été transmis',
|
||
'Reçu officiel',
|
||
'Votre planning a changé',
|
||
'Votre passage est confirmé',
|
||
'Information de dernière minute',
|
||
'Votre compte-rendu médical',
|
||
'Votre inscription est validée',
|
||
'Réponse automatique',
|
||
'Votre dossier est complet',
|
||
'Nouveau document reçu',
|
||
'Votre reçu est disponible',
|
||
'Votre commande est confirmée',
|
||
'Votre rendez-vous approche',
|
||
'Dernières informations'
|
||
];
|
||
|
||
// Liste des expéditeurs normaux
|
||
$normalSenders = [
|
||
'Docteur Martin',
|
||
'Julie',
|
||
'Paul',
|
||
'Service client',
|
||
'École primaire',
|
||
'Mairie',
|
||
'Famille Dupont',
|
||
'Pharmacie du Centre',
|
||
'EDF Service',
|
||
'Voisinage',
|
||
'Transport local',
|
||
'Maison de santé',
|
||
'Claire Bernard',
|
||
'Assurance Habitation',
|
||
'Bibliothèque municipale',
|
||
'Banque familiale',
|
||
'Centre médical',
|
||
'La Poste',
|
||
'Mutuelle Santé',
|
||
'Service facturation'
|
||
];
|
||
|
||
// Liste des sujets spam
|
||
$spamSubjects = [
|
||
'URGENT !!! VOTRE COMPTE SERA SUPPRIMÉ AUJOURD’HUI',
|
||
'FÉLICITATIONS !!! VOUS AVEZ GAGNÉ 5000 € MAINTENANT',
|
||
'CLIQUEZ ICI IMMÉDIATEMENT POUR ÉVITER LE BLOCAGE',
|
||
'VOTRE COLIS EST BLOQUÉ, PAYEZ TOUT DE SUITE',
|
||
'DERNIÈRE ALERTE : CONFIRMEZ VOTRE MOT DE PASSE',
|
||
'ACTION OBLIGATOIRE DANS LES 5 MINUTES',
|
||
'VOTRE BANQUE EXIGE UNE VÉRIFICATION IMMÉDIATE',
|
||
'RÉCUPÉREZ VOTRE CADEAU GRATUIT MAINTENANT',
|
||
'ALERTE SÉCURITÉ : VOTRE IDENTITÉ EST EN DANGER',
|
||
'VOUS ÊTES LE GRAND GAGNANT DU JOUR',
|
||
'PAIEMENT REFUSÉ !!! METTEZ À JOUR VOTRE CARTE',
|
||
'CONFIRMEZ VOS INFORMATIONS SINON FERMETURE',
|
||
'OFFRE SECRÈTE EXCEPTIONNELLE À RÉCUPÉRER',
|
||
'VOTRE SESSION EXPIRE, CLIQUEZ MAINTENANT',
|
||
'REMBOURSEMENT IMMÉDIAT DISPONIBLE ICI',
|
||
'ATTENTION !!! COMPTE BLOQUÉ DANS QUELQUES MINUTES',
|
||
'DERNIÈRE CHANCE AVANT SUPPRESSION DÉFINITIVE',
|
||
'VOTRE MOT DE PASSE A ÉTÉ PIRATÉ, AGISSEZ',
|
||
'VÉRIFICATION URGENTE DE VOTRE CARTE BANCAIRE',
|
||
'CONFIRMEZ VOTRE IDENTITÉ POUR RECEVOIR VOTRE ARGENT'
|
||
];
|
||
|
||
// Liste des expéditeurs spam
|
||
$spamSenders = [
|
||
'service-urgent@compte-bloque-now.biz',
|
||
'cadeau-gratuit@super-offre-win.click',
|
||
'banque-alerte@verification-securite.top',
|
||
'colis-stop@paiement-obligatoire.help',
|
||
'admin-compte@action-immediate.world',
|
||
'support-prime@argent-rapide-fast.support',
|
||
'verification@motdepasse-danger.win',
|
||
'alerte@compte-fermeture.click'
|
||
];
|
||
|
||
// Liste des aperçus normaux
|
||
$normalPreviews = [
|
||
'Bonjour, nous vous confirmons votre rendez-vous prévu cette semaine.',
|
||
'Je vous envoie les informations demandées, bonne journée.',
|
||
'Votre document est prêt, vous pouvez le consulter.',
|
||
'Merci pour votre message, voici les détails utiles.',
|
||
'Votre commande a bien été prise en compte.',
|
||
'Petit rappel pour ne rien oublier demain.',
|
||
'Nous restons à votre disposition pour toute question.',
|
||
'Voici un message d’information concernant votre dossier.',
|
||
'Le service vous remercie et vous souhaite une bonne journée.',
|
||
'Vous trouverez ci-joint les éléments utiles.'
|
||
];
|
||
|
||
// Liste des aperçus spam
|
||
$spamPreviews = [
|
||
'Cliquez tout de suite sinon votre compte sera fermé dans quelques minutes.',
|
||
'Paiement obligatoire immédiat pour débloquer la situation.',
|
||
'Confirmez vos données personnelles maintenant pour éviter la suppression.',
|
||
'Votre cadeau gratuit vous attend, cliquez ici sans attendre.',
|
||
'Action urgente requise, réponse dans les 5 minutes demandée.',
|
||
'Dernier avertissement officiel avant blocage définitif.'
|
||
];
|
||
|
||
function firstLetterSafe(string $text): string
|
||
{
|
||
if (function_exists('mb_substr') && function_exists('mb_strtoupper')) {
|
||
return mb_strtoupper(mb_substr($text, 0, 1, 'UTF-8'), 'UTF-8');
|
||
}
|
||
|
||
return strtoupper(substr($text, 0, 1));
|
||
}
|
||
|
||
function buildInboxRound(
|
||
array $normalSubjects,
|
||
array $normalSenders,
|
||
array $normalPreviews,
|
||
array $spamSubjects,
|
||
array $spamSenders,
|
||
array $spamPreviews,
|
||
int $maxAttempts
|
||
): array {
|
||
$normalPool = [];
|
||
foreach ($normalSubjects as $index => $subject) {
|
||
$normalPool[] = [
|
||
'id' => 'normal_' . $index,
|
||
'sender' => $normalSenders[array_rand($normalSenders)],
|
||
'subject' => $subject,
|
||
'preview' => $normalPreviews[array_rand($normalPreviews)],
|
||
'is_spam' => false,
|
||
'time' => sprintf('%02d:%02d', random_int(8, 19), random_int(0, 59))
|
||
];
|
||
}
|
||
|
||
$spamPool = [];
|
||
foreach ($spamSubjects as $index => $subject) {
|
||
$spamPool[] = [
|
||
'id' => 'spam_' . $index,
|
||
'sender' => $spamSenders[array_rand($spamSenders)],
|
||
'subject' => $subject,
|
||
'preview' => $spamPreviews[array_rand($spamPreviews)],
|
||
'is_spam' => true,
|
||
'time' => sprintf('%02d:%02d', random_int(0, 23), random_int(0, 59))
|
||
];
|
||
}
|
||
|
||
shuffle($normalPool);
|
||
shuffle($spamPool);
|
||
|
||
$selected = array_slice($normalPool, 0, 9);
|
||
$selected[] = $spamPool[0];
|
||
shuffle($selected);
|
||
|
||
return [
|
||
'token' => bin2hex(random_bytes(16)),
|
||
'correct_id' => $spamPool[0]['id'],
|
||
'emails' => $selected,
|
||
'attempts_left' => $maxAttempts
|
||
];
|
||
}
|
||
|
||
if (!isset($_SESSION['captcha_round']) || !is_array($_SESSION['captcha_round'])) {
|
||
$_SESSION['captcha_round'] = buildInboxRound(
|
||
$normalSubjects,
|
||
$normalSenders,
|
||
$normalPreviews,
|
||
$spamSubjects,
|
||
$spamSenders,
|
||
$spamPreviews,
|
||
$maxAttempts
|
||
);
|
||
}
|
||
|
||
$round = $_SESSION['captcha_round'];
|
||
$error = '';
|
||
$success = false;
|
||
$locked = false;
|
||
|
||
if (!isset($round['emails']) || !is_array($round['emails'])) {
|
||
$_SESSION['captcha_round'] = buildInboxRound(
|
||
$normalSubjects,
|
||
$normalSenders,
|
||
$normalPreviews,
|
||
$spamSubjects,
|
||
$spamSenders,
|
||
$spamPreviews,
|
||
$maxAttempts
|
||
);
|
||
$round = $_SESSION['captcha_round'];
|
||
}
|
||
|
||
// Gestion de la soumission du formulaire
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$postedToken = $_POST['captcha_token'] ?? '';
|
||
$selectedMail = $_POST['selected_mail'] ?? '';
|
||
|
||
if (!hash_equals($round['token'], $postedToken)) {
|
||
$error = 'Session invalide, recharge la page.';
|
||
} elseif (($round['attempts_left'] ?? 0) <= 0) {
|
||
$locked = true;
|
||
$error = 'Tu n’as plus d’essais. Recharge une nouvelle série.';
|
||
} elseif ($selectedMail !== $round['correct_id']) {
|
||
$_SESSION['captcha_round']['attempts_left']--;
|
||
$round = $_SESSION['captcha_round'];
|
||
|
||
if (($round['attempts_left'] ?? 0) <= 0) {
|
||
$locked = true;
|
||
$error = 'Perdu. Tu n’as plus d’essais. Recharge une nouvelle série.';
|
||
// Log Discord : visiteur bloqué au captcha (possible robot)
|
||
sendLog("Captcha raté : plus aucun essai restant (possible robot)");
|
||
} else {
|
||
$error = 'Ce n’est pas le bon mail. Regarde mieux le message le plus agressif ou trop urgent.';
|
||
// Log Discord : mauvaise réponse au captcha
|
||
sendLog("Captcha raté : mauvaise réponse (" . $round['attempts_left'] . " essai(s) restant(s))");
|
||
}
|
||
} else {
|
||
$_SESSION['captcha_valid'] = true;
|
||
unset($_SESSION['captcha_round']);
|
||
$success = true;
|
||
// Log Discord : captcha validé, le visiteur accède au site
|
||
sendLog("Captcha réussi : nouveau visiteur sur le site");
|
||
}
|
||
}
|
||
|
||
$attemptsLeft = $round['attempts_left'] ?? 0;
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Test anti-robot</title>
|
||
<link rel="icon" type="image/png" href="./memoji.png">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="./styles/captcha.css">
|
||
</head>
|
||
<body class="<?php echo $success ? 'success-mode' : ''; ?>">
|
||
<main class="captcha-shell">
|
||
<?php if ($success): ?>
|
||
<section class="success-screen">
|
||
<div class="success-burst"></div>
|
||
<div class="success-icon">✅</div>
|
||
<h1>Vérification réussie</h1>
|
||
<p>Bravo, tu as trouvé le mail frauduleux. Redirection en cours...</p>
|
||
<div class="success-loader">
|
||
<span></span>
|
||
</div>
|
||
</section>
|
||
|
||
<script>
|
||
setTimeout(function () {
|
||
window.location.href = './index.php';
|
||
}, 1800);
|
||
</script>
|
||
<?php else: ?>
|
||
<form class="captcha-card" method="post" action="">
|
||
<div class="captcha-badge">🛡️ Test anti-robot</div>
|
||
|
||
<div class="captcha-top">
|
||
<div>
|
||
<h1 class="captcha-title">Vérification humaine</h1>
|
||
<p class="captcha-subtitle">
|
||
Pour continuer, cliquez sur le <strong>mail frauduleux</strong> parmi les 10 messages ci-dessous.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="captcha-target">
|
||
<span>Vérification demandée</span>
|
||
<strong>Trouver le spam</strong>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="captcha-stats">
|
||
<div class="captcha-attempts">
|
||
<span>Essais restants</span>
|
||
<strong><?php echo htmlspecialchars((string) $attemptsLeft, ENT_QUOTES, 'UTF-8'); ?> / <?php echo htmlspecialchars((string) $maxAttempts, ENT_QUOTES, 'UTF-8'); ?></strong>
|
||
</div>
|
||
|
||
<?php if ($locked): ?>
|
||
<a class="captcha-reset" href="./captcha.php?reload=1">Recharger une nouvelle série</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<?php if ($error !== ''): ?>
|
||
<div class="captcha-error"><?php echo htmlspecialchars($error, ENT_QUOTES, 'UTF-8'); ?></div>
|
||
<?php endif; ?>
|
||
|
||
<div class="mailbox">
|
||
<div class="mailbox-toolbar">
|
||
<div class="mailbox-dots">
|
||
<span></span>
|
||
<span></span>
|
||
<span></span>
|
||
</div>
|
||
<div class="mailbox-label">Test anti-robot : trouvez le mail qui ressemble à une arnaque</div>
|
||
</div>
|
||
|
||
<div class="mail-list">
|
||
<?php foreach ($round['emails'] as $mail): ?>
|
||
<label class="mail-option <?php echo $locked ? 'mail-option-disabled' : ''; ?>">
|
||
<input
|
||
type="radio"
|
||
name="selected_mail"
|
||
value="<?php echo htmlspecialchars($mail['id'], ENT_QUOTES, 'UTF-8'); ?>"
|
||
<?php echo $locked ? 'disabled' : 'required'; ?>
|
||
>
|
||
<span class="mail-row">
|
||
<span class="mail-avatar">
|
||
<?php echo htmlspecialchars(firstLetterSafe($mail['sender']), ENT_QUOTES, 'UTF-8'); ?>
|
||
</span>
|
||
|
||
<span class="mail-sender">
|
||
<?php echo htmlspecialchars($mail['sender'], ENT_QUOTES, 'UTF-8'); ?>
|
||
</span>
|
||
|
||
<span class="mail-content">
|
||
<span class="mail-subject">
|
||
<?php echo htmlspecialchars($mail['subject'], ENT_QUOTES, 'UTF-8'); ?>
|
||
</span>
|
||
<span class="mail-preview">
|
||
<?php echo htmlspecialchars($mail['preview'], ENT_QUOTES, 'UTF-8'); ?>
|
||
</span>
|
||
</span>
|
||
|
||
<span class="mail-time">
|
||
<?php echo htmlspecialchars($mail['time'], ENT_QUOTES, 'UTF-8'); ?>
|
||
</span>
|
||
</span>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<input
|
||
type="hidden"
|
||
name="captcha_token"
|
||
value="<?php echo htmlspecialchars($round['token'], ENT_QUOTES, 'UTF-8'); ?>"
|
||
>
|
||
|
||
<div class="captcha-footer">
|
||
<p class="captcha-note">
|
||
Tu as plusieurs essais. Les faux mails utilisent souvent l’urgence, les cadeaux improbables, les menaces ou les demandes de mot de passe.
|
||
</p>
|
||
|
||
<div class="captcha-actions">
|
||
<?php if ($locked): ?>
|
||
<a class="captcha-secondary-button" href="./captcha.php?reload=1">Nouvelle série</a>
|
||
<?php else: ?>
|
||
<button type="submit" class="captcha-submit">Valider ma sélection</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
<?php endif; ?>
|
||
</main>
|
||
</body>
|
||
</html>
|