// ==================== МОДУЛЬ АВТОЛОГИНА ==================== (function() { const core = window.VideoIPRedirect; if (!core) { console.error('[VideoIPRedirect] CORE не загружен!'); return; } const debugLog = (msg, ...args) => core.debugLog('autologin', msg, ...args); debugLog('🔐 Загрузка модуля...'); // Получить профиль по индексу function getProfile(index) { const profiles = core.CONFIG.autologin.profiles; if (!Array.isArray(profiles) || profiles.length === 0) return null; const idx = (typeof index === 'number' && index >= 0 && index < profiles.length) ? index : 0; return profiles[idx] || profiles[0]; } // Найти правило подсети для текущего хоста function getSubnetRule() { const host = window.location.hostname; const rules = core.CONFIG.autologin.subnetRules || []; return rules.find(r => r.subnet && host.startsWith(r.subnet)) || null; } // Проверка страницы логина типа 1 (порт 5000, /login, поля username/password) function isLoginPage1() { if (window.location.port !== '5000') return false; if (!window.location.pathname.includes('/login')) return false; const usernameField = document.querySelector('input[name="username"]'); const passwordField = document.querySelector('input[name="password"]'); return !!(usernameField && passwordField); } // Проверка страницы логина типа 2 (auth-logo.png + react-notification-root + noscript) function isLoginPage2() { const hasNoscript = Array.from(document.querySelectorAll('noscript')) .some(n => n.textContent.includes('You need to enable JavaScript to run this app')); if (!hasNoscript) return false; const hasNotificationRoot = !!document.querySelector('div.react-notification-root, div[class*="react-notification-root"]'); if (!hasNotificationRoot) return false; const hasAuthLogo = !!document.querySelector('img[src="/images/auth-logo.png"]'); if (!hasAuthLogo) return false; return true; } // Заполнить форму логина данными профиля и нажать кнопку входа function performLoginWithProfile(profile) { if (!profile || !profile.username || !profile.password) { debugLog('⚠️ Профиль не задан или пустые учётные данные'); return false; } const usernameField = document.querySelector('input[name="username"]'); const passwordField = document.querySelector('input[name="password"]'); const submitButton = document.querySelector('button[type="submit"]'); if (!usernameField || !passwordField) { debugLog('❌ Не удалось найти поля ввода'); return false; } debugLog(`✍️ Заполнение полей (профиль: ${profile.name || 'без имени'})...`); // React перехватывает нативный сеттер value — используем его напрямую, // чтобы обновление дошло до React-state компонента const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSetter.call(usernameField, profile.username); usernameField.dispatchEvent(new Event('input', { bubbles: true })); nativeSetter.call(passwordField, profile.password); passwordField.dispatchEvent(new Event('input', { bubbles: true })); debugLog('✅ Поля заполнены'); const autoSubmit = typeof profile.autoSubmit === 'boolean' ? profile.autoSubmit : true; if (autoSubmit && submitButton) { const delay = profile.delay || 500; debugLog(`⏱️ Вход через ${delay}мс...`); setTimeout(() => { debugLog('🚀 Нажатие кнопки "Вход"'); submitButton.click(); }, delay); } else { debugLog('ℹ️ Автоматический вход отключен'); } return true; } // Главная функция автологина для страницы типа 1 (с retry-логикой) function performAutoLogin() { debugLog('========== ПРОВЕРКА АВТОЛОГИНА (тип 1) =========='); if (!core.CONFIG.autologin.enabled) { debugLog('⏹ Автологин отключен в настройках'); return false; } if (!isLoginPage1()) { debugLog('❌ Это не страница логина типа 1'); return false; } debugLog('✅ Обнаружена страница логина типа 1'); // Проверяем правила подсетей const rule = getSubnetRule(); if (rule) { debugLog(`📋 Найдено правило подсети: "${rule.subnet}", действие: "${rule.action}"`); if (rule.action === 'skip') { debugLog('⏭ Автологин пропущен по правилу подсети'); return false; } if (rule.action === 'profile') { const overrideProfile = getProfile(rule.profileIndex); debugLog(`🔄 Используем профиль по правилу подсети: ${overrideProfile?.name}`); return performLoginWithProfile(overrideProfile); } } const profile = getProfile(core.CONFIG.autologin.profilePage1); debugLog(`🔑 Профиль для типа 1: ${profile?.name}`); return performLoginWithProfile(profile); } // Автологин для страницы типа 1 — с повторными попытками function tryAutoLogin(attempts = 3) { debugLog(`🔄 Попытка автологина типа 1 (осталось попыток: ${attempts})`); const success = performAutoLogin(); if (!success && attempts > 0) { setTimeout(() => tryAutoLogin(attempts - 1), 500); } } // Автологин для страницы типа 2 — одна попытка, без retry function performAutoLoginPage2() { debugLog('========== ПРОВЕРКА АВТОЛОГИНА (тип 2) =========='); if (!core.CONFIG.autologin.enabled) { debugLog('⏹ Автологин отключен в настройках'); return false; } if (!isLoginPage2()) { debugLog('❌ Это не страница логина типа 2'); return false; } debugLog('✅ Обнаружена страница логина типа 2'); // Проверяем правила подсетей const rule = getSubnetRule(); if (rule) { debugLog(`📋 Найдено правило подсети: "${rule.subnet}", действие: "${rule.action}"`); if (rule.action === 'skip') { debugLog('⏭ Автологин пропущен по правилу подсети'); return false; } if (rule.action === 'profile') { const overrideProfile = getProfile(rule.profileIndex); debugLog(`🔄 Используем профиль по правилу подсети: ${overrideProfile?.name}`); return performLoginWithProfile(overrideProfile); } } const profile = getProfile(core.CONFIG.autologin.profilePage2); debugLog(`🔑 Профиль для типа 2: ${profile?.name}`); return performLoginWithProfile(profile); // Намеренно без retry — одна попытка } // Однократный вход по кнопке из попапа (без проверки enabled, всегда отправка формы) function performLoginOnce() { if (!isLoginPage1() && !isLoginPage2()) { return { ok: false, error: 'not_login_page' }; } const isPage2 = isLoginPage2(); const profileIndex = isPage2 ? core.CONFIG.autologin.profilePage2 : core.CONFIG.autologin.profilePage1; const profile = getProfile(profileIndex); if (!profile || !profile.username || !profile.password) { return { ok: false, error: 'no_credentials' }; } const usernameField = document.querySelector('input[name="username"]'); const passwordField = document.querySelector('input[name="password"]'); if (!usernameField || !passwordField) { return { ok: false, error: 'no_fields' }; } const nativeSetter2 = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSetter2.call(usernameField, profile.username); usernameField.dispatchEvent(new Event('input', { bubbles: true })); nativeSetter2.call(passwordField, profile.password); passwordField.dispatchEvent(new Event('input', { bubbles: true })); const submitButton = document.querySelector('button[type="submit"]'); if (submitButton) { const delay = profile.delay || 500; setTimeout(() => submitButton.click(), delay); } return { ok: true, profileName: profile.name || '' }; } // Публичный API window.VideoIPRedirect.AutoLogin = { tryAutoLogin: tryAutoLogin, performAutoLoginPage2: performAutoLoginPage2, isLoginPage1: isLoginPage1, isLoginPage2: isLoginPage2, performLoginOnce: performLoginOnce, getProfile: getProfile, getSubnetRule: getSubnetRule }; debugLog('✅ Модуль загружен'); })();