<?php
if (session_status() == PHP_SESSION_NONE) {
    session_start();
}

require_once($_SERVER['DOCUMENT_ROOT'].'/admin/config.php');

$config = get_config();

$captcha_passed = isset($_SESSION['captcha_passed']) && $_SESSION['captcha_passed'] === true;

function blockIp($ip) {
	$block_file = __DIR__ . '/admin/files/blocked/blocked_ips.txt';
	file_put_contents($block_file, $ip . PHP_EOL, FILE_APPEND | LOCK_EX);
}

function isBlocked($ip) {
	$block_file = __DIR__ . '/admin/files/blocked/blocked_ips.txt';
	if (!empty($block_file) && file_exists($block_file)) {
		$blocked_ips = file($block_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
		return in_array($ip, $blocked_ips);
	}
	return false;
}

function blocked($msg) {
    global $config;
    echo <<<HTML
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Access Denied</title>
   <style>
      body, html {
         height: 100%;
         margin: 0;
         padding: 0;
         font-family: Arial, sans-serif;
      }
      
      body {
         display: flex;
         justify-content: center;
         align-items: center;
         background-color: #f5f5f5;
      }
      
      .outer {
         width: 100%;
         max-width: 500px;
         padding: 2rem;
         text-align: center;
      }
      
      .inner {
         background-color: white;
         border-radius: 8px;
         padding: 2rem;
         box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
      }
      
      img {
         max-width: 200px;
         height: auto;  
         margin-bottom: 1.5rem;
      }
      
      .text-title {
         font-size: 1.5rem;
         font-weight: bold;
         margin-bottom: 1rem;
         color: #333;
      }
      
      .form-group {
         font-size: 1rem;
         color: #666;
         line-height: 1.5;
      }
   </style>
</head>
<body>
   <div class="outer">
      <div class="inner">
         <div class="text-title" role="heading" aria-level="1">Access Denied</div>
         <div class="form-group">{$msg}</div>
      </div>
   </div>
</body>
</html>
HTML;
    exit();
}

function getIpAddress() {
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        return $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        return $_SERVER['REMOTE_ADDR'];
    }
}

function getIPDetails($ip) {
    $api_url = 'https://api.findip.net/' . $ip . '/?token=000e63e9964845a693b5dcd40dfd6a9d';
    $response = @file_get_contents($api_url);
    $data = json_decode($response, true);
    return $data;
}

if (isBlocked(getIpAddress())) {
	blocked("You are blocked from accessing this site");
    exit;
}

if ($captcha_passed) {
    return;
}

$should_check = true;
if (isset($_SESSION['last_ip']) && $_SESSION['last_ip'] === getIpAddress()) {
    $should_check = false;
}

if ($should_check) {
    if (!isset($_SESSION['ip_details'])) {
        $ip_details = getIPDetails(getIpAddress());
        $_SESSION['ip_details'] = $ip_details;
        $_SESSION['last_ip'] = getIpAddress();
    }
}

if ($config['ANTIBOT_SETTINGS']['block_vpn']) {
    if (isset($_SESSION['ip_details']['traits']) && 
        isset($_SESSION['ip_details']['traits']['user_type'])) {
        $ip_type = $_SESSION['ip_details']['traits']['user_type'];
        if ($ip_type == 'hosting') {
            blocked("It seems you are accessing this site using a VPN or a hosting IP. Please disable your VPN and try again");
			exit;
        }
    }
}

function isAllowedCountry($ipDetails, $config) {
    if (empty($config['ANTIBOT_SETTINGS']['allow_country'])) {
        return true;
    }

    $allowed_countries = array_map('trim', explode(',', $config['ANTIBOT_SETTINGS']['allow_country']));
    
    if (isset($ipDetails['country']['iso_code'])) {
        return in_array($ipDetails['country']['iso_code'], $allowed_countries);
    }
    
    return false;
}

if (!isAllowedCountry($_SESSION['ip_details'], $config)) {
    blocked("Access from your country is not allowed.");
}

// Handle captcha validation from the rotating image captcha
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['action']) && $_GET['action'] === 'validate') {
    $input = json_decode(file_get_contents('php://input'), true);
    
    // Validate CSRF token
    if (!isset($input['csrfToken']) || !isset($_SESSION['captcha_csrf']) || 
        $input['csrfToken'] !== $_SESSION['captcha_csrf']) {
        echo json_encode(['success' => false, 'error' => 'Invalid CSRF token']);
        exit;
    }
    
    // Check completion time (prevent bots)
    if (isset($input['completionTime']) && $input['completionTime'] < 500) {
        $_SESSION['captcha_passed'] = false;
        blockIp(getIpAddress());
        echo json_encode(['success' => false, 'error' => 'Validation failed']);
        exit;
    }
    
    // Validate the degree
    $correctDegree = isset($_SESSION['captcha_degree']) ? $_SESSION['captcha_degree'] : 0;
    $inputDegree = isset($input['inputDegree']) ? intval($input['inputDegree']) : 0;
    $tolerance = 15; // Degrees tolerance
    
    $diff = abs($correctDegree - $inputDegree);
    if ($diff <= $tolerance || $diff >= (360 - $tolerance)) {
        $_SESSION['captcha_passed'] = true;
        
        // Log visitor
        $log_file = __DIR__ . '/admin/files/logs/all_logs.json';
        if (file_exists($log_file)) {
            $json_data = json_decode(file_get_contents($log_file), true);
            $json_data['visitors'] = isset($json_data['visitors']) ? $json_data['visitors'] + 1 : 1;
            file_put_contents($log_file, json_encode($json_data, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
        } else {
            $json_data = ['visitors' => 1, 'all_logs' => []];
            file_put_contents($log_file, json_encode($json_data, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
        }
        
        echo json_encode(['success' => true, 'message' => 'Correct! Thank you!']);
    } else {
        echo json_encode(['success' => false, 'error' => 'Incorrect match, please try again.']);
    }
    exit;
}

// Initialize captcha data
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'init') {
    $imageIndex = rand(1, 10);
    $correctDegree = rand(0, 360);
    $csrfToken = bin2hex(random_bytes(32));
    
    $_SESSION['captcha_degree'] = $correctDegree;
    $_SESSION['captcha_csrf'] = $csrfToken;
    
    echo json_encode([
        'success' => true,
        'imageIndex' => $imageIndex,
        'correctDegree' => $correctDegree,
        'csrfToken' => $csrfToken
    ]);
    exit;
}


?>
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Prove you are human!</title>
    <link rel="stylesheet" href="https://public.codepenassets.com/css/normalize-5.0.0.min.css">
    <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css'>
	<meta name="viewport" content="width=device-width,initial-scale=1" />

    <style>
body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  background: #f5f7fa;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.app {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  background: white;
  padding: 2.5rem 2rem;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  max-width: 450px;
  width: 100%;
}

.app h3 {
  margin: 0 0 1.5rem 0;
  font-size: 1.3rem;
  font-weight: 600;
  color: #2c3e50;
  text-align: center;
  line-height: 1.4;
}

.captcha-base {
  width: 12rem;
  height: 12rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bgImage) no-repeat center center;
  background-size: cover;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.captcha-base .captcha-inner {
  width: calc(12rem - 5rem);
  height: calc(12rem - 5rem);
  border: 2px solid rgba(255, 255, 255, 0.6);
  border-radius: 50%;
  background: var(--bgImage) no-repeat center center;
  background-size: 12rem;
  transform: rotate(var(--degree));
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

input[type=range] {
  -webkit-appearance: none;
  width: 100%;
  max-width: 320px;
  height: 6px;
  border-radius: 3px;
  background: #e0e7ef;
  outline: none;
  cursor: pointer;
}

input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #5a67d8;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  transition: all 0.15s ease;
}

input[type=range]::-webkit-slider-thumb:hover {
  background: #4c51bf;
  transform: scale(1.1);
}

input[type=range]::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 50%;
  background: #5a67d8;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  transition: all 0.15s ease;
}

input[type=range]::-moz-range-thumb:hover {
  background: #4c51bf;
  transform: scale(1.1);
}

input[type=range]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

button {
  background: #5a67d8;
  color: white;
  border: none;
  padding: 10px 32px;
  font-size: 0.95rem;
  font-weight: 500;
  border-radius: 6px;
  cursor: pointer;
  visibility: hidden;
  box-shadow: 0 2px 4px rgba(90, 103, 216, 0.25);
  transition: all 0.2s ease;
}

button:hover:not(:disabled) {
  background: #4c51bf;
  box-shadow: 0 3px 6px rgba(90, 103, 216, 0.35);
}

button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.refresh-btn {
  background: transparent;
  color: #718096;
  border: none;
  padding: 8px 16px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  visibility: visible !important;
  box-shadow: none;
  transition: color 0.2s ease;
  text-decoration: underline;
}

.refresh-btn:hover:not(:disabled) {
  color: #5a67d8;
  background: transparent;
  box-shadow: none;
}

.refresh-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

code {
  visibility: hidden;
  font-size: 0.9rem;
  padding: 8px 16px;
  border-radius: 4px;
  font-weight: 500;
}

code.info {
  color: #2f855a;
  background: #f0fdf4;
  border: 1px solid #86efac;
}

code:not(.info) {
  color: #c53030;
  background: #fef2f2;
  border: 1px solid #fca5a5;
}

@media (max-width: 600px) {
  .app {
    padding: 2rem 1.5rem;
  }
  
  .captcha-base {
    width: 11rem;
    height: 11rem;
  }
  
  .captcha-base .captcha-inner {
    width: calc(11rem - 5rem);
    height: calc(11rem - 5rem);
    background-size: 11rem;
  }
}
    </style>

  </head>
    
  <body>
  <div id="root"></div>
    <script type="module">
import React, {
useRef,
useEffect,
useState,
useCallback } from
"https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const captchaImages = [
"https://picsum.photos/400/400?random=1",
"https://picsum.photos/400/400?random=2",
"https://picsum.photos/400/400?random=3",
"https://picsum.photos/400/400?random=4",
"https://picsum.photos/400/400?random=5",
"https://picsum.photos/400/400?random=6",
"https://picsum.photos/400/400?random=7",
"https://picsum.photos/400/400?random=8",
"https://picsum.photos/400/400?random=9",
"https://picsum.photos/400/400?random=10"];

const API_URL = "?";

const Captcha = ({ image, degree }) => {
  return /*#__PURE__*/(
    React.createElement("div", {
      className: "captcha-base",
      style: {
        "--bgImage": `url(${image})`,
        "--degree": `${degree}deg` } }, /*#__PURE__*/


    React.createElement("div", { className: "captcha-inner" })));


};

const App = () => {
  const degreeRef = useRef(0);
  const messageRef = useRef(null);
  const validateBtnRef = useRef(null);
  const startTimeRef = useRef(null);
  const csrfTokenRef = useRef(null);

  const [inputDegree, setInputDegree] = useState(0);
  const [randomImage, setRandomImage] = useState("");
  const [loading, setLoading] = useState(true);
  const [validated, setValidated] = useState(false);

  const initializeCaptcha = useCallback(async () => {
    try {
      setLoading(true);
      const response = await fetch(`${API_URL}action=init`);
      const data = await response.json();
      
      if (data.success) {
        degreeRef.current = data.correctDegree || 0;
        const imageUrl = captchaImages[data.imageIndex - 1] || captchaImages[0];
        csrfTokenRef.current = data.csrfToken;
        
        // Preload the image before displaying
        const img = new Image();
        img.crossOrigin = "anonymous";
        
        img.onload = () => {
          setRandomImage(imageUrl);
          startTimeRef.current = Date.now();
          setLoading(false);
        };
        
        img.onerror = () => {
          console.error("Failed to load image:", imageUrl);
          if (messageRef.current) {
            messageRef.current.innerText = "Error loading image. Please refresh.";
            messageRef.current.style.visibility = "visible";
          }
          setLoading(false);
        };
        
        img.src = imageUrl;
      } else {
        throw new Error(data.error || "Failed to initialize CAPTCHA");
      }
    } catch (error) {
      console.error("Error initializing CAPTCHA:", error);
      if (messageRef.current) {
        messageRef.current.innerText = "Error loading CAPTCHA. Please refresh.";
        messageRef.current.style.visibility = "visible";
      }
      setLoading(false);
    }
  }, []);

  const showInfo = (visible = false) => {
    if (messageRef.current) {
      messageRef.current.style.visibility = visible ? "visible" : "hidden";
    }
  };

  const handleMessage = (success = false, message = null) => {
    if (messageRef.current) {
      messageRef.current.innerText = message || (success ?
      "Correct! Thank you!" :
      "Incorrect match, please try again.");
      if (success) {
        messageRef.current.classList.add("info");
      } else {
        messageRef.current.classList.remove("info");
      }
    }
  };

  useEffect(() => {
    initializeCaptcha();
  }, [initializeCaptcha]);

  const handleInputDegree = ({ target }) => {
    if (!messageRef.current || validated) return;

    messageRef.current.classList.remove("info");
    const newInputDegree = Number(target.value);
    setInputDegree(newInputDegree);
    showInfo(false);
  };

  const validateDegree = async () => {
    if (validated || !csrfTokenRef.current) return;
    
    showInfo(true);
    
    try {
      const completionTime = Date.now() - (startTimeRef.current || Date.now());
      
      const response = await fetch(`${API_URL}action=validate`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          inputDegree: inputDegree,
          csrfToken: csrfTokenRef.current,
          completionTime: completionTime
        })
      });
      
      const data = await response.json();
      
      if (data.success) {
        setValidated(true);
        handleMessage(true, data.message || "Correct! Thank you!");
        if (validateBtnRef.current) {
          validateBtnRef.current.disabled = true;
        }
        
        // Reload page after success
        setTimeout(() => {
          window.location.reload();
        }, 1000);
      } else {
        handleMessage(false, data.error || "Incorrect match, please try again.");
        // Reset CAPTCHA on failure
        setTimeout(() => {
          initializeCaptcha();
          setInputDegree(0);
          if (validateBtnRef.current) {
            validateBtnRef.current.style.visibility = "hidden";
          }
        }, 2000);
      }
    } catch (error) {
      console.error("Error validating CAPTCHA:", error);
      handleMessage(false, "Error validating. Please try again.");
    }
  };

  const handleSliderRelease = () => {
    if (validated) return;
    
    if (inputDegree !== 0) {
      validateBtnRef.current.style.visibility = "visible";
    } else {
      validateBtnRef.current.style.visibility = "hidden";
    }
  };

  const handleRefresh = () => {
    if (validated) return;
    
    setInputDegree(0);
    if (messageRef.current) {
      messageRef.current.style.visibility = "hidden";
      messageRef.current.classList.remove("info");
    }
    if (validateBtnRef.current) {
      validateBtnRef.current.style.visibility = "hidden";
    }
    initializeCaptcha();
  };

  if (loading) {
    return /*#__PURE__*/(
      React.createElement("div", { className: "app" }, /*#__PURE__*/
      React.createElement("h3", null, "Loading CAPTCHA...")));
  }

  return /*#__PURE__*/(
    React.createElement("div", { className: "app" },
      /*#__PURE__*/React.createElement("h3", { style: { textAlign: 'center' } },
        React.createElement(React.Fragment, null,
          "Prove you are human!",
          React.createElement("br", null),
          "Complete the CAPTCHA by matching the correct angle"
        )
      ),
    React.createElement(Captcha, { image: randomImage, degree: degreeRef.current + inputDegree }), /*#__PURE__*/
    React.createElement("input", {
      type: "range",
      min: 0,
      max: 360,
      value: inputDegree,
      onChange: handleInputDegree,
      onMouseUp: handleSliderRelease,
      onTouchEnd: handleSliderRelease,
      disabled: validated }), /*#__PURE__*/

    React.createElement("button", { 
      onClick: validateDegree, 
      ref: validateBtnRef,
      disabled: validated || loading }, "Validate"), /*#__PURE__*/

    React.createElement("button", { 
      onClick: handleRefresh,
      className: "refresh-btn",
      disabled: validated || loading }, "Refresh Image"), /*#__PURE__*/


    React.createElement("code", { ref: messageRef, className: "message" })));


};

ReactDOM.render( /*#__PURE__*/React.createElement(App, null), document.getElementById("root"));
    </script>

  </body>
  
</html>

<?php
exit;
?>