<!doctype html>
<html lang="bg">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Bot checking</title>
  <style>
    body {font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; display:flex; align-items:center; justify-content:center; height:100vh; margin:0; background:#f6f7fb;}
    .card {background:#fff; padding:28px; border-radius:12px; box-shadow:0 8px 30px rgba(20,20,50,0.08); width:420px; text-align:center;}
    .spinner {margin:16px auto; width:36px; height:36px; border-radius:50%; border:4px solid #eee; border-top-color:#3b82f6; animation:spin 1s linear infinite;}
    @keyframes spin {to{transform:rotate(360deg)}}
    button {margin-top:12px; padding:8px 14px; border-radius:8px; border:0; background:#3b82f6; color:white; cursor:pointer;}
    .hidden{display:none}
    iframe.captcha {width:320px; height:78px; border:0; margin-top:12px;}
    small {color:#666}
  </style>
</head>
<body>
  <div class="card" id="card">
    <h2>Checking </h2>
    <div id="status">
      <div class="spinner" id="spinner"></div>
      <div id="text">Verifieng…</div>
      <small id="subtext">This helps tp protect the site from automated requests..</small>
    </div>

    <!-- Ако проверката не премине, тук ще покажем CAPTCHA/възможност за продължаване -->
    <div id="challenge" class="hidden">
      <div id="captchaContainer"></div>
      <div style="margin-top:10px">
        <button id="retryBtn">Try again</button>
      </div>
    </div>
  </div>

<script>
/*
  Как работи:
  - page accepts a query param "dest" — URL към който да се пренасочи след успешна валидация.
  - прави няколко клиентски теста (cookies, localStorage, requestAnimationFrame, plugins).
  - ако score >= threshold => изпраща малък POST към /bot_verify.php с времeн токен.
  - само след успешна отговорка от сървъра потребителят се пренасочва към `dest`.
  - иначе показваме CAPTCHA (интеграция с reCAPTCHA/hCaptcha) — след валидна CAPTCHA също POST-ваме към /bot_verify.php.
*/

(function(){
  const THRESHOLD = 3; // колко "пойнта" са нужни (регулирай)
  const VERIFY_ENDPOINT = "/bot_verify.php"; // endpoint на сървъра, виж по-долу PHP пример
  const CAPTCHA_PROVIDER = "recaptcha"; // "recaptcha" или "hcaptcha" или null
  const RECAPTCHA_SITE_KEY = "6LfC3P4SAAAAAE3FCDOgZSnD8rS10IQGUvL2hxfY"; // замени с твоя ключ
  const HCAPTCHA_SITE_KEY = "YOUR_HCAPTCHA_SITE_KEY"; // ако ползваш hcaptcha

  const card = document.getElementById('card');
  const text = document.getElementById('text');
  const spinner = document.getElementById('spinner');
  const challenge = document.getElementById('challenge');
  const captchaContainer = document.getElementById('captchaContainer');
  const retryBtn = document.getElementById('retryBtn');

  // helper: get dest param (fallback to /)
  function getDest() {
    try {
      const u = new URL(window.location.href);
      const dest = u.searchParams.get('f') || '/';
	  return window.location.href;
      // return dest;
    } catch(e){ return '/'; }
  }

  // generate ephemeral token stored in cookie/localStorage
  function generateToken() {
    return 't_' + Math.random().toString(36).slice(2) + Date.now().toString(36);
  }

  function setCookie(name, value, secs) {
    const d = new Date(Date.now() + (secs||60)*1000);
    document.cookie = `${name}=${encodeURIComponent(value)}; path=/; expires=${d.toUTCString()}; SameSite=Lax`;
  }
  function readCookie(name) {
    return document.cookie.split('; ').reduce((acc, kv) => {
      const [k,v] = kv.split('=');
      if(k===name) acc = decodeURIComponent(v);
      return acc;
    }, undefined);
  }

  // client-side tests returning points
  function runClientChecks() {
    let score = 0;
    // 1) cookies enabled
    try {
      const ckTest = 'ck_' + Math.random().toString(36).slice(2);
      setCookie(ckTest, '1', 10);
      if (readCookie(ckTest) === '1') score++;
    } catch(e){}

    // 2) localStorage available
    try {
      const lsTest = 'ls_' + Math.random().toString(36).slice(2);
      localStorage.setItem(lsTest, '1');
      if (localStorage.getItem(lsTest) === '1') { score++; localStorage.removeItem(lsTest); }
    } catch(e){}

    // 3) requestAnimationFrame exists and runs quickly
    if (typeof requestAnimationFrame === 'function' && typeof performance !== 'undefined') {
      score++;
    }

    // 4) navigator plugins / mimeTypes (naive check)
    try {
      if (navigator && (navigator.plugins && navigator.plugins.length > 0 || navigator.mimeTypes && navigator.mimeTypes.length > 0)) {
        score++;
      } else {
        // even if zero, still not fatal (some headless browsers are 0)
      }
    } catch(e){}

    // 5) timezone offset plausible
    try {
      const tz = new Date().getTimezoneOffset();
      if (typeof tz === 'number') score++;
    } catch(e){}

    return score;
  }

  // Small behavioral check: wait briefly for a user input (mousemove/touchstart) but do not block long
  function waitForHumanInteraction(timeoutMs=2000) {
    return new Promise(resolve => {
      let resolved = false;
      function onInteract(){ if(!resolved){ resolved = true; cleanup(); resolve(true);} }
      function cleanup(){
        window.removeEventListener('mousemove', onInteract);
        window.removeEventListener('touchstart', onInteract);
        window.removeEventListener('keydown', onInteract);
      }
      window.addEventListener('mousemove', onInteract, {passive:true});
      window.addEventListener('touchstart', onInteract, {passive:true});
      window.addEventListener('keydown', onInteract, {passive:true});
      setTimeout(()=>{ if(!resolved){ resolved=true; cleanup(); resolve(false); } }, timeoutMs);
    });
  }

  // POST small verification to server with ephemeral token and client evidence.
  async function postVerify(token, evidence, captchaToken=null) {
    try {
      const body = { token, evidence, captchaToken, dest: getDest() };
      const res = await fetch(VERIFY_ENDPOINT, {
        method: 'POST',
        credentials: 'include', // allow server to set session cookie
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body)
      });
      if (!res.ok) throw new Error('verify failed: '+res.status);
      const j = await res.json();
      return j; // expect { ok: true, redirect: '/...' } or {ok:false, reason: ''}
    } catch (err) {
      console.error(err);
      return { ok:false, reason: err.message };
    }
  }

  // show CAPTCHA (basic approach: reCAPTCHA v2/invisible or hCaptcha)
  function showCaptcha() {
    spinner.classList.add('hidden');
    challenge.classList.remove('hidden');
    text.textContent = 'Моля, попълнете captcha-то, за да продължите.';
    captchaContainer.innerHTML = '';

    if (CAPTCHA_PROVIDER === 'recaptcha') {
      // render reCAPTCHA v2 checkbox (placeholder; assumes grecaptcha loaded)
      // You must include <script src="https://www.google.com/recaptcha/api.js" async defer>< /script> in production or load dynamically.
      const wrapper = document.createElement('div');
      wrapper.innerHTML = `<div class="g-recaptcha" data-sitekey="${RECAPTCHA_SITE_KEY}"></div>`;
      captchaContainer.appendChild(wrapper);
      // Optionally load script dynamically:
      if (!window.grecaptcha) {
        const s = document.createElement('script');
        s.src = 'https://www.google.com/recaptcha/api.js';
        s.async = true; s.defer = true;
        document.head.appendChild(s);
      }
    } else if (CAPTCHA_PROVIDER === 'hcaptcha') {
      const wrapper = document.createElement('div');
      wrapper.innerHTML = `<div class="h-captcha" data-sitekey="${HCAPTCHA_SITE_KEY}"></div>`;
      captchaContainer.appendChild(wrapper);
      if (!window.hcaptcha) {
        const s = document.createElement('script');
        s.src = 'https://hcaptcha.com/1/api.js';
        s.async = true; s.defer = true;
        document.head.appendChild(s);
      }
    } else {
      // fallback: simple "click to continue" (less secure)
      const btn = document.createElement('button');
      btn.textContent = 'Покажи страницата';
      btn.onclick = () => {
        attemptVerification(null); // no captcha token
      };
      captchaContainer.appendChild(btn);
    }
  }

  // main flow
  async function mainFlow() {
    const token = generateToken();
    // store temporary token both in cookie and localStorage (server will match)
    setCookie('gate_token', token, 60);
    try { localStorage.setItem('gate_token', token); } catch(e){}

    text.textContent = 'Collect browser features…';

    const baseScore = runClientChecks();
    const humanInteraction = await waitForHumanInteraction(1500);
    let score = baseScore + (humanInteraction ? 1 : 0);

    // small honeypot: a property rarely present in headless contexts
    try { if (navigator.webdriver !== true) score++; } catch(e){}

    console.log('client evidence score=', score);

    if (score >= THRESHOLD) {
      text.textContent = 'Successfull automated verification — server confirmation...';
      // send evidence to server
      const evidence = { score, baseScore, humanInteraction, ua: navigator.userAgent, tzOffset: new Date().getTimezoneOffset() };
      spinner.classList.remove('hidden');
      const result = await postVerify(token, evidence, null);

      if (result && result.ok) {
        text.textContent = 'Valid — redirection...';
        // server can return redirect or we redirect to dest
        const dest = result.redirect || getDest();
		// alert(dest);
        window.location.replace(dest);
        return;
      } else {
        console.warn('Server refused auto-verify:', result && result.reason);
        // show captcha as fallback
        showCaptcha();
      }
    } else {
      // low score -> show captcha
      showCaptcha();
    }
  }

  // retry button if captcha flow fails
  retryBtn.addEventListener('click', () => {
    spinner.classList.remove('hidden');
    challenge.classList.add('hidden');
    text.textContent = 'Проверяваме отново…';
    spinner.classList.remove('hidden');
    // Try again but likely will show captcha again — for simplicity we reload page
    setTimeout(()=> location.reload(), 400);
  });

  // If using reCAPTCHA/hCaptcha you'd hook their callback to call attemptVerification(captchaToken).
  window.attemptVerification = async function(captchaToken) {
    spinner.classList.remove('hidden');
    challenge.classList.add('hidden');
    text.textContent = 'Изпращаме резултата към сървъра…';
    const token = readCookie('gate_token') || localStorage.getItem('gate_token') || generateToken();
    const evidence = { score: 0, captchaUsed: !!captchaToken, ua:navigator.userAgent };
    const result = await postVerify(token, evidence, captchaToken);
    if (result && result.ok) {
      text.textContent = 'Valid — redirection...';
      const dest = result.redirect || getDest();
      window.location.replace(dest);
	  // alert(dest);
    } else {
      text.textContent = 'Ivalid verification.';
      spinner.classList.add('hidden');
      challenge.classList.remove('hidden');
      // optionally display reason
    }
  };

  // start
  mainFlow();
})();
</script>
</body>
</html>
