class CookieManager { get(cname) { let name = cname + "="; const nameEQ = encodeURIComponent(name) + "="; const cookies = document.cookie.split('; '); for (let cookie of cookies) { if (cookie.startsWith(nameEQ)) { return decodeURIComponent(cookie.substring(nameEQ.length)); } } return null; } set(cname, cvalue, exdays) { const d = new Date(); d.setTime(d.getTime() + (exdays*24*60*60*1000)); let expires = "expires="+ d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; } // Check if a cookie is set has(name) { return this.get(name) !== null; } // Delete a cookie delete(name) { this.set(name, '', -1); } // Get all cookies as object getAll() { return document.cookie .split('; ') .reduce((acc, curr) => { const [key, val] = curr.split('='); acc[decodeURIComponent(key)] = decodeURIComponent(val); return acc; }, {}); } } class BotDetector { constructor() { this.flags = { headlessBrowser: false, noUserInteraction: true, unusualUserAgent: false, fastLoad: false, }; this._userInteractionDetected = false; this._startTime = performance.now(); this._setupListeners(); } _setupListeners() { const interactionHandler = () => { this.flags.noUserInteraction = false; this._userInteractionDetected = true; }; window.addEventListener('mousemove', interactionHandler); window.addEventListener('keydown', interactionHandler); window.addEventListener('touchstart', interactionHandler); window.addEventListener('scroll', interactionHandler); } _checkHeadlessBrowser() { if ( navigator.webdriver || /HeadlessChrome/.test(navigator.userAgent) || !navigator.userAgent ) { this.flags.headlessBrowser = true; } } _checkUserAgent() { const suspiciousAgents = ['PhantomJS', 'HeadlessChrome', 'Selenium', 'Python', 'Scrapy']; if (suspiciousAgents.some(agent => navigator.userAgent.includes(agent))) { this.flags.unusualUserAgent = true; } } _checkLoadTime() { const loadTime = performance.now() - this._startTime; if (loadTime < 100) { this.flags.fastLoad = true; } } async detect() { // Wait a bit to allow for interaction await new Promise(resolve => setTimeout(resolve, 2000)); this._checkHeadlessBrowser(); this._checkUserAgent(); this._checkLoadTime(); //const isBot = Object.values(this.flags).some(Boolean); const botScore = (this.flags.headlessBrowser ? 2 : 0) + (this.flags.unusualUserAgent ? 1 : 0) + (this.flags.fastLoad ? 1 : 0) + (this.flags.noUserInteraction ? 0.5 : 0); // smaller weight const isBot = botScore >= 2; // Tune threshold return { isBot, details: this.flags, botScore: botScore }; } } class Fingerprint { constructor() { this.fingerprintData = {}; } async generate() { this.fingerprintData.userAgent = navigator.userAgent; this.fingerprintData.language = navigator.language; this.fingerprintData.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; this.fingerprintData.screen = { width: screen.width, height: screen.height, colorDepth: screen.colorDepth, pixelDepth: screen.pixelDepth, }; this.fingerprintData.hardware = { deviceMemory: navigator.deviceMemory || 'unknown', hardwareConcurrency: navigator.hardwareConcurrency || 'unknown', }; this.fingerprintData.touchSupport = { maxTouchPoints: navigator.maxTouchPoints || 0, touchEvent: 'ontouchstart' in window, }; this.fingerprintData.storage = { localStorage: this._hasLocalStorage(), sessionStorage: this._hasSessionStorage(), indexedDB: this._hasIndexedDB(), }; this.fingerprintData.permissions = await this._getPermissionsStatus(); const jsonString = JSON.stringify(this.fingerprintData); return await this._hash(jsonString); } _hasLocalStorage() { try { return !!window.localStorage; } catch { return false; } } _hasSessionStorage() { try { return !!window.sessionStorage; } catch { return false; } } _hasIndexedDB() { return !!window.indexedDB; } async _getPermissionsStatus() { const permissions = ['geolocation', 'notifications', 'camera', 'microphone']; const results = {}; for (const name of permissions) { try { const status = await navigator.permissions.query({ name }); results[name] = status.state; } catch { results[name] = 'unsupported'; } } return results; } async _hash(input) { const encoder = new TextEncoder(); const data = encoder.encode(input); const hashBuffer = await crypto.subtle.digest('SHA-256', data); return Array.from(new Uint8Array(hashBuffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } } const detector = new BotDetector(); const cookieManager = new CookieManager(); //alert(yii.getCsrfToken()); (async () => { if (!cookieManager.has('ncooks')) { const fp = new Fingerprint(); const fingerprintHash = await fp.generate(); //console.log('Your fingerprint:', fingerprintHash); cookieManager.set('ncooks', fingerprintHash); let nboos = null; detector.detect().then(result => { if (!cookieManager.has('nboos')) { nboos = result.botScore; cookieManager.set('nboos', result.botScore, 31); if (result.isBot) { //console.log('is bot'); cookieManager.set('nboos', 0, 31); } else if (!result.isBot) { cookieManager.set('nboos', 1, 31); //console.log('is not bot'); } } //console.log(result.botScore + ' and ' + !cookieManager.has('nboo')); if (result.isBot) { //console.warn('Bot detected!', result.details); // You can redirect, show CAPTCHA, log, etc. } else { //console.log('Human visitor detected.'); } }).then(function() { fetch('/saveui', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': yii.getCsrfToken() }, body: JSON.stringify({ fpHash: fingerprintHash, nboos: nboos, currAction: window.location.href }) }).then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); // parse JSON response //console.log(response); //let responseJson = response.json(); //let navLoader = $('#navbar-loader'); //console.log(responseJson); //if (responseJson.success) { // navLoader.hide('slow'); // alert('test'); //} }).then(data => { let navLoader = $('#navbar-loader-cont'); if (data.success) { //navLoader.stop(true, true).fadeOut(300); // 300ms fade-out navLoader.addClass('d-none'); // fetch latest fetch('/site/empty').then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.text(); }).then(html => { // grab the navbar after logging in let jHtml = $('
' + html + '
'); let jHtmlNav = jHtml.find('.r-nav-place'); $('.r-nav-place').html(jHtmlNav); }); } }); }); } })();