Deeper Tools

Набор инструментов для Deeper: автоавторизация, белый список, сканер доменов.

当前为 2025-04-14 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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);
        }
    }

})();