您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Набор инструментов для Deeper: автоавторизация, белый список, сканер доменов.
当前为
// ==UserScript== // @name Deeper Tools // @description Набор инструментов для Deeper: автоавторизация, белый список, сканер доменов. // @author https://github.com/lReDragol // @namespace http://tampermonkey.net/ // @version 3.0 // @icon https://avatars.mds.yandex.net/get-socsnippets/10235467/2a0000019509580bc84108597cea65bc46ee/square_83 // @match http://34.34.34.34/* // @match *://*/* // @license MIT // @run-at document-start // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function() { 'use strict'; function getScannerEnabled() { return GM_getValue('domainScannerEnabled', false); } function setScannerEnabled(val) { GM_setValue('domainScannerEnabled', val); updateScannerMenuCommand(); if (!val) { const container = document.getElementById('domain-scanner-container'); if (container) container.remove(); } else { ensureScannerContainer(); } console.log('[Deeper Tools] Domain Scanner: ' + (val ? 'ON' : 'OFF')); } const nativeOpen = XMLHttpRequest.prototype.open; const nativeSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; if (getScannerEnabled()) { try { const urlObj = new URL(url); addDomain(urlObj.hostname); } catch(e) {} } return nativeOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { if ( this._url && this._url.includes('/api/admin/login') && this._method && this._method.toUpperCase() === 'POST' ) { try { const parsed = JSON.parse(body); if (parsed && parsed.password) { if (!localStorage.getItem('adminPassword')) { localStorage.setItem('adminPassword', parsed.password); console.log('[Deeper Tools] Пароль сохранён из XHR.'); } } } catch (err) { console.error('[Deeper Tools] Ошибка парсинга XHR при авторизации:', err); } } return nativeSend.apply(this, arguments); }; if (window.location.href.includes('/login/')) { const storedPassword = localStorage.getItem('adminPassword'); if (storedPassword) { window.addEventListener('load', () => { fetch('http://34.34.34.34/api/admin/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "username": "admin", "password": storedPassword }) }) .then(response => { if (response.status === 200) { window.location.href = 'http://34.34.34.34/admin/dashboard'; } return response.json(); }) .then(data => console.log('[Deeper Tools] Авторизация прошла успешно:', data)) .catch(error => console.error('[Deeper Tools] Ошибка при авторизации:', error)); }); } else { console.log('[Deeper Tools] Пароль не найден. Выполните ручную авторизацию.'); } } if (window.location.href.startsWith('http://34.34.34.34/')) { const iconButton = document.createElement('div'); iconButton.style.position = 'fixed'; iconButton.style.width = '25px'; iconButton.style.height = '25px'; iconButton.style.top = '10px'; iconButton.style.right = '10px'; iconButton.style.zIndex = '9999'; iconButton.style.backgroundColor = 'rgb(240, 240, 252)'; iconButton.style.borderRadius = '4px'; iconButton.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)'; iconButton.style.cursor = 'pointer'; iconButton.style.display = 'flex'; iconButton.style.alignItems = 'center'; iconButton.style.justifyContent = 'center'; const img = document.createElement('img'); img.src = 'https://avatars.mds.yandex.net/get-socsnippets/10235467/2a0000019509580bc84108597cea65bc46ee/square_83'; img.style.maxWidth = '80%'; img.style.maxHeight = '80%'; iconButton.appendChild(img); const menuContainer = document.createElement('div'); menuContainer.style.position = 'fixed'; menuContainer.style.top = '45px'; menuContainer.style.right = '10px'; menuContainer.style.zIndex = '10000'; menuContainer.style.padding = '10px'; menuContainer.style.border = '1px solid #ccc'; menuContainer.style.borderRadius = '5px'; menuContainer.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)'; menuContainer.style.backgroundColor = '#fff'; menuContainer.style.display = 'none'; menuContainer.style.flexDirection = 'column'; function toggleMenu() { menuContainer.style.display = (menuContainer.style.display === 'none') ? 'flex' : 'none'; } iconButton.addEventListener('click', toggleMenu); const buttonStyle = { margin: '5px 0', padding: '6px 10px', backgroundColor: '#f8f8f8', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer', fontSize: '14px' }; const downloadBtn = document.createElement('button'); downloadBtn.textContent = 'Скачать'; Object.assign(downloadBtn.style, buttonStyle); const uploadBtn = document.createElement('button'); uploadBtn.textContent = 'Загрузить'; Object.assign(uploadBtn.style, buttonStyle); const disableRebootBtn = document.createElement('button'); disableRebootBtn.textContent = 'Отключить перезагрузку'; Object.assign(disableRebootBtn.style, buttonStyle); const forgetBtn = document.createElement('button'); forgetBtn.textContent = 'Забыть пароль'; Object.assign(forgetBtn.style, buttonStyle); menuContainer.appendChild(downloadBtn); menuContainer.appendChild(uploadBtn); menuContainer.appendChild(disableRebootBtn); menuContainer.appendChild(forgetBtn); function ensureMenu() { if (!document.body.contains(iconButton)) { document.body.appendChild(iconButton); } if (!document.body.contains(menuContainer)) { document.body.appendChild(menuContainer); } } document.addEventListener('DOMContentLoaded', ensureMenu); new MutationObserver(ensureMenu).observe(document.documentElement, { childList: true, subtree: true }); async function getExistingWhitelist() { const pageSize = 100; let pageNo = 1; let total = 0; let allItems = []; let firstIteration = true; do { const url = `http://34.34.34.34/api/smartRoute/getRoutingWhitelist/domain?pageNo=${pageNo}&pageSize=${pageSize}`; const response = await fetch(url); if (!response.ok) { throw new Error('Ошибка при запросе списка на странице ' + pageNo); } const data = await response.json(); if (firstIteration) { total = data.total; firstIteration = false; } if (data.list && data.list.length > 0) { allItems = allItems.concat(data.list); } pageNo++; } while (allItems.length < total); return allItems; } downloadBtn.addEventListener('click', async () => { downloadBtn.disabled = true; downloadBtn.textContent = 'Скачивание...'; try { const allItems = await getExistingWhitelist(); const finalData = { total: allItems.length, list: allItems }; const blob = new Blob([JSON.stringify(finalData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'data.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } catch (error) { console.error('[Deeper Tools] Ошибка при скачивании:', error); alert('Ошибка при скачивании данных. Проверьте консоль.'); } downloadBtn.textContent = 'Скачать'; downloadBtn.disabled = false; }); uploadBtn.addEventListener('click', () => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'application/json'; input.style.display = 'none'; input.addEventListener('change', async function() { if (input.files.length === 0) return; const file = input.files[0]; const reader = new FileReader(); reader.onload = async function(e) { try { const jsonData = JSON.parse(e.target.result); if (!jsonData.list || !Array.isArray(jsonData.list)) { throw new Error('Неверный формат файла: ожидалось поле list[].'); } const fileDomainNames = jsonData.list.map(item => item.domainName); const existing = await getExistingWhitelist(); const existingDomainNames = existing.map(item => item.domainName); const duplicates = fileDomainNames.filter(d => existingDomainNames.includes(d)); if (duplicates.length > 0) { console.log('[Deeper Tools] Удаляем дубликаты:', duplicates); const delRes = await fetch('http://34.34.34.34/api/smartRoute/deleteFromWhitelist/domain', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(duplicates) }); if (!delRes.ok) { console.error('[Deeper Tools] Ошибка при удалении дубликатов:', duplicates); } } // Добавляем все из файла for (let item of jsonData.list) { const payload = { domainName: item.domainName, tunnelCode: item.tunnelCode }; const res = await fetch('http://34.34.34.34/api/smartRoute/addToWhitelist/domain', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!res.ok) { console.error('[Deeper Tools] Ошибка добавления домена:', item.domainName); } } alert('[Deeper Tools] Данные успешно загружены!'); } catch(err) { console.error('[Deeper Tools] Ошибка загрузки:', err); alert('Ошибка загрузки. Смотрите консоль.'); } }; reader.readAsText(file); }); document.body.appendChild(input); input.click(); document.body.removeChild(input); }); disableRebootBtn.addEventListener('click', async () => { disableRebootBtn.disabled = true; disableRebootBtn.textContent = 'Отключение...'; try { const queryParams = '?on=false&hour=0&minute=0&day=0'; const response = await fetch(`http://34.34.34.34/api/autoReboot/config${queryParams}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error('Ошибка при отключении перезагрузки'); } alert('[Deeper Tools] Перезагрузка отключена!'); } catch (error) { console.error('[Deeper Tools] Ошибка отключения перезагрузки:', error); alert('Ошибка отключения перезагрузки. Смотрите консоль.'); } disableRebootBtn.textContent = 'Отключить перезагрузку'; disableRebootBtn.disabled = false; }); forgetBtn.addEventListener('click', () => { if (confirm('Внимание! Логин и пароль будут очищены. Продолжить?')) { localStorage.removeItem('adminPassword'); alert('[Deeper Tools] Пароль очищен. Авторизуйтесь вручную.'); } }); } const domainSet = new Set(); const originalFetch = window.fetch; window.fetch = function(input, init) { if (getScannerEnabled()) { try { const url = (typeof input === 'string') ? input : input.url; const urlObj = new URL(url); addDomain(urlObj.hostname); } catch(e) {} } return originalFetch.apply(this, arguments); }; const observer = new MutationObserver(mutations => { if (!getScannerEnabled()) return; mutations.forEach(m => { if (m.addedNodes) { m.addedNodes.forEach(node => { if (node.tagName) { const src = node.src || node.href; if (src) { try { const urlObj = new URL(src); addDomain(urlObj.hostname); } catch(e) {} } } }); } }); }); observer.observe(document.documentElement, { childList: true, subtree: true }); setInterval(() => { if (!getScannerEnabled()) return; const entries = performance.getEntriesByType('resource'); entries.forEach(entry => { try { const urlObj = new URL(entry.name); addDomain(urlObj.hostname); } catch(e) {} }); }, 1000); function addDomain(domain) { if (!domainSet.has(domain)) { domainSet.add(domain); const container = document.getElementById('domain-scanner-container'); if (container) { const listEl = container.querySelector('#domain-list'); const sortedArr = Array.from(domainSet).sort(); listEl.textContent = sortedArr.join('\n'); } } } function ensureScannerContainer() { if (!getScannerEnabled()) return; if (document.getElementById('domain-scanner-container')) return; const container = document.createElement('div'); container.id = 'domain-scanner-container'; container.style.position = 'fixed'; container.style.top = '10px'; container.style.right = '10px'; container.style.width = '300px'; container.style.height = '400px'; container.style.overflowY = 'scroll'; container.style.backgroundColor = 'white'; container.style.border = '1px solid black'; container.style.zIndex = '10000'; container.style.padding = '10px'; container.style.fontSize = '12px'; container.style.fontFamily = 'monospace'; container.style.color = 'black'; container.style.whiteSpace = 'pre-wrap'; const domainList = document.createElement('div'); domainList.id = 'domain-list'; container.appendChild(domainList); const buttonWrapper = document.createElement('div'); buttonWrapper.style.marginTop = '10px'; const addBtn = document.createElement('button'); addBtn.textContent = 'Добавить в deeper'; Object.assign(addBtn.style, { padding: '6px 10px', backgroundColor: '#f8f8f8', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer', fontSize: '14px' }); addBtn.addEventListener('click', addToDeeper); buttonWrapper.appendChild(addBtn); container.appendChild(buttonWrapper); document.body.appendChild(container); } async function addToDeeper() { try { const resp = await fetch('http://34.34.34.34/api/smartRoute/getRoutingWhitelist/domain?pageNo=1&pageSize=100'); if (!resp.ok) { alert('[Deeper Tools] Ошибка при получении белого списка'); return; } const data = await resp.json(); const existingDomains = new Set(); const tunnelCodes = []; if (Array.isArray(data.list)) { data.list.forEach(item => { if (item.domainName) existingDomains.add(item.domainName); if (item.tunnelCode) tunnelCodes.push(item.tunnelCode); }); } if (tunnelCodes.length === 0) { tunnelCodes.push('defaultCode'); } const newItems = []; domainSet.forEach(d => { if (!existingDomains.has(d)) { const randomIndex = Math.floor(Math.random() * tunnelCodes.length); newItems.push({ domainName: d, tunnelCode: tunnelCodes[randomIndex] }); } }); if (newItems.length === 0) { alert('[Deeper Tools] Нет новых доменов для добавления.'); return; } for (let item of newItems) { const r = await fetch('http://34.34.34.34/api/smartRoute/addToWhitelist/domain', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(item) }); if (!r.ok) { console.error('[Deeper Tools] Ошибка при добавлении домена:', item); } } alert('[Deeper Tools] Новые домены добавлены в deeper!'); } catch (err) { console.error('[Deeper Tools] Ошибка при добавлении в deeper:', err); alert('Ошибка при добавлении. Смотрите консоль.'); } } let scannerMenuCommandId = null; function updateScannerMenuCommand() { if (scannerMenuCommandId && typeof GM_unregisterMenuCommand === 'function') { GM_unregisterMenuCommand(scannerMenuCommandId); } if (typeof GM_registerMenuCommand === 'function') { const currentState = getScannerEnabled(); const label = 'Domain Scanner: ' + (currentState ? '🟢' : '🔴'); scannerMenuCommandId = GM_registerMenuCommand(label, () => { setScannerEnabled(!getScannerEnabled()); }); } } if (GM_getValue('domainScannerEnabled') === undefined) { GM_setValue('domainScannerEnabled', false); } updateScannerMenuCommand(); if (getScannerEnabled()) { if (document.readyState === 'complete' || document.readyState === 'interactive') { ensureScannerContainer(); } else { document.addEventListener('DOMContentLoaded', ensureScannerContainer); } } })();