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