<?php
/**
 * index.php — Antibot autonome (fichier unique)
 * Canvas + WebGL + Fonts + Honeypot + interaction invisible.
 * Vérification TOUT-OU-RIEN (pas de score) : un seul test raté => bloqué.
 *
 * OK   -> redirige vers suite.php
 * PAS OK -> redirige vers bloque.html
 */

session_start();

// ---------- Réglages ----------
define('MIN_DELAY_MS', 900);   // délai mini entre affichage et soumission (anti-script instantané)
define('MAX_DELAY_MS', 30000); // délai maxi avant expiration du token
define('FONT_MIN_COUNT', 3);   // nb mini de polices détectées

define('WEBGL_BLACKLIST', [
    'swiftshader', 'llvmpipe', 'mesa offscreen', 'google swiftshader',
    'microsoft basic render', 'vmware, inc.', 'virtualbox',
]);

define('UA_BLACKLIST', [
    'headlesschrome', 'phantomjs', 'selenium', 'puppeteer', 'playwright',
    'python-requests', 'curl/', 'wget/', 'httpclient', 'scrapy', 'bot', 'spider', 'crawler',
]);

// ---------- Fonctions de vérification ----------
function isBlacklistedUserAgent(): bool {
    $ua = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
    if ($ua === '') return true;
    foreach (UA_BLACKLIST as $needle) {
        if (strpos($ua, $needle) !== false) return true;
    }
    return false;
}

function honeypotPassed(array $p): bool {
    return isset($p['website']) && $p['website'] === '';
}

function tokenPassed(array $p): bool {
    if (empty($_SESSION['page_token']) || empty($_SESSION['page_token_time'])) return false;
    if (!isset($p['page_token']) || !hash_equals($_SESSION['page_token'], $p['page_token'])) return false;
    $elapsedMs = (microtime(true) - $_SESSION['page_token_time']) * 1000;
    return $elapsedMs >= MIN_DELAY_MS && $elapsedMs <= MAX_DELAY_MS;
}

function webdriverPassed(array $p): bool {
    return ($p['webdriver'] ?? '1') === '0';
}

function canvasPassed(array $p): bool {
    $data = $p['canvas_data'] ?? '';
    return is_string($data) && strlen($data) > 120;
}

function webglPassed(array $p): bool {
    if (($p['webgl_supported'] ?? '0') !== '1') return false;
    $renderer = strtolower($p['webgl_renderer'] ?? '');
    $vendor = strtolower($p['webgl_vendor'] ?? '');
    if ($renderer === '' && $vendor === '') return false;
    foreach (WEBGL_BLACKLIST as $needle) {
        if (strpos($renderer, $needle) !== false || strpos($vendor, $needle) !== false) return false;
    }
    return true;
}

function fontsPassed(array $p): bool {
    return (int)($p['font_count'] ?? 0) >= FONT_MIN_COUNT;
}

function interactionPassed(array $p): bool {
    return ($p['interacted'] ?? '0') === '1';
}

function verifyAll(array $p): bool {
    return !isBlacklistedUserAgent()
        && honeypotPassed($p)
        && tokenPassed($p)
        && webdriverPassed($p)
        && canvasPassed($p)
        && webglPassed($p)
        && fontsPassed($p)
        && interactionPassed($p);
}

// ---------- Endpoint AJAX de vérification ----------
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'verify') {
    header('Content-Type: application/json; charset=utf-8');
    if (verifyAll($_POST)) {
        echo json_encode(['status' => 'ok', 'redirect' => 'suite.php']);
    } else {
        echo json_encode(['status' => 'blocked', 'redirect' => 'bloque.html']);
    }
    exit;
}

// ---------- Génération du token pour cette page-vue ----------
$pageToken = bin2hex(random_bytes(24));
$_SESSION['page_token'] = $pageToken;
$_SESSION['page_token_time'] = microtime(true);
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title>Vérification en cours...</title>
<style>
  html, body {
    margin: 0; height: 100%; background: #f4f4f5;
    display: flex; align-items: center; justify-content: center;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  }
  .gate-card {
    width: 280px; padding: 40px 24px; background: #fff;
    border-radius: 16px; box-shadow: 0 4px 24px rgba(0,0,0,0.06); text-align: center;
  }
  .spinner {
    width: 40px; height: 40px; margin: 0 auto 20px; border-radius: 50%;
    border: 3px solid #e4e4e7; border-top-color: #2563eb; animation: spin .8s linear infinite;
  }
  @keyframes spin { to { transform: rotate(360deg); } }
  .gate-text { color: #52525b; font-size: 14px; letter-spacing: .2px; }
  .hp-field { position: absolute; left: -9999px; top: -9999px; height: 0; width: 0; overflow: hidden; }
</style>
</head>
<body>

  <div class="gate-card">
    <div class="spinner"></div>
    <div class="gate-text"></div>
  </div>

  <form id="hp-form" class="hp-field" autocomplete="off">
    <label for="website">Site web</label>
    <input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
  </form>

  <script>
  (function () {
    "use strict";
    var PAGE_TOKEN = <?php echo json_encode($pageToken); ?>;
    var interacted = false;

    function markInteracted() { interacted = true; }
    window.addEventListener('mousemove', markInteracted, { once: true, passive: true });
    window.addEventListener('touchstart', markInteracted, { once: true, passive: true });
    window.addEventListener('keydown', markInteracted, { once: true, passive: true });
    window.addEventListener('scroll', markInteracted, { once: true, passive: true });
    setTimeout(function () { if (!interacted) markInteracted(); }, 600);

    function getCanvasData() {
      try {
        var c = document.createElement('canvas');
        c.width = 220; c.height = 40;
        var ctx = c.getContext('2d');
        if (!ctx) return '';
        ctx.textBaseline = 'top';
        ctx.font = '14px Arial';
        ctx.fillStyle = '#f60';
        ctx.fillRect(0, 0, 100, 20);
        ctx.fillStyle = '#069';
        ctx.fillText('fingerprint-check-🔒', 2, 15);
        ctx.strokeStyle = 'rgba(102,204,0,0.7)';
        ctx.beginPath();
        ctx.arc(50, 20, 15, 0, Math.PI * 2);
        ctx.stroke();
        return c.toDataURL();
      } catch (e) { return ''; }
    }

    function getWebglInfo() {
      var info = { supported: false, renderer: '', vendor: '' };
      try {
        var c = document.createElement('canvas');
        var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
        if (!gl) return info;
        info.supported = true;
        var dbg = gl.getExtension('WEBGL_debug_renderer_info');
        if (dbg) {
          info.renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
          info.vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) || '';
        } else {
          info.renderer = gl.getParameter(gl.RENDERER) || '';
          info.vendor = gl.getParameter(gl.VENDOR) || '';
        }
      } catch (e) {}
      return info;
    }

    function countAvailableFonts() {
      var baseFonts = ['monospace', 'sans-serif', 'serif'];
      var testFonts = [
        'Arial', 'Verdana', 'Times New Roman', 'Courier New', 'Georgia',
        'Comic Sans MS', 'Impact', 'Tahoma', 'Trebuchet MS', 'Segoe UI', 'Helvetica'
      ];
      var testString = 'mmmmmmmmmmlli';
      var span = document.createElement('span');
      span.style.position = 'absolute';
      span.style.left = '-9999px';
      span.style.fontSize = '72px';
      span.style.visibility = 'hidden';
      span.textContent = testString;
      document.body.appendChild(span);

      var baseWidths = {};
      baseFonts.forEach(function (bf) {
        span.style.fontFamily = bf;
        baseWidths[bf] = span.offsetWidth;
      });

      var detected = 0;
      testFonts.forEach(function (tf) {
        var isDetected = baseFonts.some(function (bf) {
          span.style.fontFamily = "'" + tf + "', " + bf;
          return span.offsetWidth !== baseWidths[bf];
        });
        if (isDetected) detected++;
      });

      document.body.removeChild(span);
      return detected;
    }

    function runChecksAndSubmit() {
      var canvasData = getCanvasData();
      var webgl = getWebglInfo();
      var fontCount = countAvailableFonts();
      var honeypotValue = document.getElementById('website').value;
      var webdriverFlag = navigator.webdriver ? '1' : '0';

      var body = new URLSearchParams();
      body.append('action', 'verify');
      body.append('page_token', PAGE_TOKEN);
      body.append('website', honeypotValue);
      body.append('canvas_data', canvasData);
      body.append('webgl_supported', webgl.supported ? '1' : '0');
      body.append('webgl_renderer', webgl.renderer);
      body.append('webgl_vendor', webgl.vendor);
      body.append('font_count', String(fontCount));
      body.append('interacted', interacted ? '1' : '0');
      body.append('webdriver', webdriverFlag);

      fetch(window.location.pathname, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body.toString(),
        credentials: 'same-origin'
      })
      .then(function (r) { return r.json(); })
      .then(function (data) { window.location.href = data.redirect || 'bloque.html'; })
      .catch(function () { window.location.href = 'bloque.html'; });
    }

    setTimeout(runChecksAndSubmit, 1200);
  })();
  </script>

</body>
</html>
