LINUX.ORG.RU

Простейший переключатель прокси для chromium (может кому пригодится)

 ,


0

1

manifest.json


{
  "manifest_version": 3,
  "name": "Proxy Settings Extension",
  "version": "1.0",
  "description": "Set proxy type, IP, and port for Chrome.",
  "permissions": [
    "proxy",
    "storage"
  ],
  "host_permissions": [
    "http://*/*",
    "https://*/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}


background.js


chrome.runtime.onInstalled.addListener(() => {
  // Инициализация значений по умолчанию для прокси
  for (let i = 1; i <= 3; i++) {
    chrome.storage.sync.get([`proxyType${i}`, `proxyIP${i}`, `proxyPort${i}`], (data) => {
      if (!data[`proxyType${i}`]) {
        chrome.storage.sync.set({
          [`proxyType${i}`]: 'SOCKS5',
          [`proxyIP${i}`]: '0.0.0.0',
          [`proxyPort${i}`]: '1080'
        });
      }
    });
  }
});

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === 'get-proxy-status') {
    chrome.proxy.settings.get({}, (config) => {
      const proxyIsActive = config.value && config.value.mode === 'fixed_servers';
      if (proxyIsActive) {
        chrome.storage.sync.get(['activeProxyProfile'], (data) => {
          const activeProfile = data.activeProxyProfile || 1;
          sendResponse({ active: true, activeProfile });
        });
      } else {
        sendResponse({ active: false });
      }
    });
    return true;
  }

  if (message.action === 'apply-proxy') {
    const profile = message.profile;
    chrome.storage.sync.get([`proxyType${profile}`, `proxyIP${profile}`, `proxyPort${profile}`], (data) => {
      const proxyType = data[`proxyType${profile}`] || 'SOCKS5';
      const proxyIP = data[`proxyIP${profile}`] || '0.0.0.0';
      const proxyPort = data[`proxyPort${profile}`] || '1080';

      if (!isValidPort(proxyPort)) {
        sendResponse({ success: false, error: 'Invalid proxy port number' });
        return;
      }

      const config = {
        mode: "fixed_servers",
        rules: {
          singleProxy: {
            scheme: proxyType.toLowerCase(),
            host: proxyIP,
            port: parseInt(proxyPort, 10)
          },
          bypassList: []
        }
      };

      chrome.proxy.settings.set({ value: config, scope: 'regular' }, () => {
        if (chrome.runtime.lastError) {
          sendResponse({ success: false, error: chrome.runtime.lastError.message });
        } else {
          chrome.storage.sync.set({ activeProxyProfile: profile }, () => {
            sendResponse({ success: true });
          });
        }
      });
    });
    return true;
  }

  if (message.action === 'disable-all-proxies') {
    const config = { mode: "direct" };
    chrome.proxy.settings.set({ value: config, scope: 'regular' }, () => {
      if (chrome.runtime.lastError) {
        sendResponse({ success: false, error: chrome.runtime.lastError.message });
      } else {
        chrome.storage.sync.remove('activeProxyProfile', () => {
          sendResponse({ success: true });
        });
      }
    });
    return true;
  }
});

function isValidPort(port) {
  const parsedPort = parseInt(port, 10);
  return !isNaN(parsedPort) && parsedPort > 0 && parsedPort <= 65535;
}

function isValidIP(ip) {
  // Простейшая проверка на формат IP-адреса
  const regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
  return regex.test(ip);
}


popup.html


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Proxy Settings</title>
  <style>
    body {
      width: 600px;
      padding: 20px;
      font-family: Arial, sans-serif;
      background: linear-gradient(to bottom, #F7F7F7, #ECECEC);
    }
    .header-container {
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 20px;
    }
    h3 {
      margin: 0;
      font-size: 16px;
      text-align: left;
      margin-left: 20px;
      color: #333;
    }
    #disable-proxy {
      font-size: 12px;
      padding: 5px 10px;
      background-color: #e57373;
      color: white;
      border: none;
      cursor: pointer;
      border-radius: 5px;
      display: inline-block;
      opacity: 0.8;
    }
    #disable-proxy:hover {
      opacity: 1;
      background-color: #f44336;
    }
    #disable-proxy:disabled {
      background-color: #ccc;
      cursor: not-allowed;
      opacity: 0.8;
    }
    label {
      display: block;
      margin-top: 10px;
      font-weight: bold;
      color: #555;
    }
    input, select {
      width: 100%;
      padding: 5px;
      margin-top: 5px;
      box-sizing: border-box;
      border: 1px solid #ddd;
      border-radius: 4px;
    }
    .profiles-container {
      display: flex;
      justify-content: space-between;
      flex-wrap: wrap;
      margin: 0;
      padding: 0;
    }
    .profile {
      flex: 1 1 170px;
      border: 1px solid #ddd;
      padding: 15px;
      border-radius: 5px;
      margin: 10px;
      box-sizing: border-box;
      max-width: 170px;
      background-color: #fff;
    }
    .apply-proxy {
      width: 100%;
      margin-top: 20px;
      margin-bottom: 10px;
      padding: 10px;
      background-color: #64b5f6;
      color: white;
      border: none;
      cursor: pointer;
      border-radius: 5px;
      text-align: center;
      opacity: 0.8;
    }
    .apply-proxy:hover {
      background-color: #42a5f5;
      opacity: 1;
    }
    .apply-proxy:disabled {
      background-color: #ccc;
      cursor: not-allowed;
      opacity: 0.8;
    }
  </style>
</head>
<body>
  <div class="header-container">
    <button id="disable-proxy" disabled>Disable Proxy</button>
    <h3 id="proxy-status">Proxy OFF</h3>
  </div>

  <div class="profiles-container">
    <div class="profile">
      <label for="proxy-type-1">Proxy Type</label>
      <select id="proxy-type-1">
        <option value="SOCKS5">SOCKS5</option>
        <option value="HTTP">HTTP</option>
        <option value="HTTPS">HTTPS</option>
      </select>

      <label for="proxy-ip-1">Proxy IP</label>
      <input type="text" id="proxy-ip-1" value="0.0.0.0">

      <label for="proxy-port-1">Proxy Port</label>
      <input type="number" id="proxy-port-1" value="1080">
      
      <button class="apply-proxy" id="apply-proxy-1">Apply Proxy</button>
    </div>

    <div class="profile">
      <label for="proxy-type-2">Proxy Type</label>
      <select id="proxy-type-2">
        <option value="SOCKS5">SOCKS5</option>
        <option value="HTTP">HTTP</option>
        <option value="HTTPS">HTTPS</option>
      </select>

      <label for="proxy-ip-2">Proxy IP</label>
      <input type="text" id="proxy-ip-2" value="0.0.0.0">

      <label for="proxy-port-2">Proxy Port</label>
      <input type="number" id="proxy-port-2" value="1080">
      
      <button class="apply-proxy" id="apply-proxy-2">Apply Proxy</button>
    </div>

    <div class="profile">
      <label for="proxy-type-3">Proxy Type</label>
      <select id="proxy-type-3">
        <option value="SOCKS5">SOCKS5</option>
        <option value="HTTP">HTTP</option>
        <option value="HTTPS">HTTPS</option>
      </select>

      <label for="proxy-ip-3">Proxy IP</label>
      <input type="text" id="proxy-ip-3" value="0.0.0.0">

      <label for="proxy-port-3">Proxy Port</label>
      <input type="number" id="proxy-port-3" value="1080">
      
      <button class="apply-proxy" id="apply-proxy-3">Apply Proxy</button>
    </div>
  </div>

  <script src="popup.js"></script>
</body>
</html>


popup.js


document.addEventListener('DOMContentLoaded', () => {
  chrome.runtime.sendMessage({ action: 'get-proxy-status' }, (response) => {
    if (response && response.active) {
      document.getElementById('proxy-status').textContent = `Proxy Active (Profile ${response.activeProfile})`;
      document.getElementById('disable-proxy').disabled = false;
    } else {
      document.getElementById('proxy-status').textContent = 'Proxy OFF';
      document.getElementById('disable-proxy').disabled = true;
    }

    // Загрузка сохраненных значений в поля ввода
    for (let i = 1; i <= 3; i++) {
      chrome.storage.sync.get([`proxyType${i}`, `proxyIP${i}`, `proxyPort${i}`], (data) => {
        document.getElementById(`proxy-type-${i}`).value = data[`proxyType${i}`] || 'SOCKS5';
        document.getElementById(`proxy-ip-${i}`).value = data[`proxyIP${i}`] || '0.0.0.0';
        document.getElementById(`proxy-port-${i}`).value = data[`proxyPort${i}`] || '1080';
      });
    }
  });

  // Обработчик для кнопки "Применить прокси"
  for (let i = 1; i <= 3; i++) {
    const applyButton = document.getElementById(`apply-proxy-${i}`);
    if (applyButton) {
      applyButton.addEventListener('click', () => {
        const proxyType = document.getElementById(`proxy-type-${i}`).value;
        const proxyIP = document.getElementById(`proxy-ip-${i}`).value;
        const proxyPort = document.getElementById(`proxy-port-${i}`).value;

        if (!isValidPort(proxyPort)) {
          alert('Invalid proxy port number');
          return;
        }

        if (!isValidIP(proxyIP)) {
          alert('Invalid proxy IP address');
          return;
        }

        chrome.storage.sync.set({ [`proxyType${i}`]: proxyType, [`proxyIP${i}`]: proxyIP, [`proxyPort${i}`]: proxyPort }, () => {
          chrome.runtime.sendMessage({ action: 'apply-proxy', profile: i }, (response) => {
            if (response.success) {
              document.getElementById('proxy-status').textContent = `Proxy Active (Profile ${i})`;
              document.getElementById('disable-proxy').disabled = false;
            } else {
              alert(`Error applying proxy: ${response.error || 'Unknown error'}`);
            }
          });
        });
      });
    } else {
      console.error(`Button with id 'apply-proxy-${i}' not found.`);
    }
  }

  // Обработчик для кнопки "Отключить прокси"
  const disableProxyButton = document.getElementById('disable-proxy');
  if (disableProxyButton) {
    disableProxyButton.addEventListener('click', () => {
      chrome.runtime.sendMessage({ action: 'disable-all-proxies' }, (response) => {
        if (response.success) {
          document.getElementById('proxy-status').textContent = 'Proxy OFF';
          document.getElementById('disable-proxy').disabled = true;
        } else {
          alert(`Error disabling proxy: ${response.error || 'Unknown error'}`);
        }
      });
    });
  }

  // Слушаем изменения в полях ввода, чтобы сохранять данные при вводе
  for (let i = 1; i <= 3; i++) {
    const proxyTypeElement = document.getElementById(`proxy-type-${i}`);
    const proxyIPElement = document.getElementById(`proxy-ip-${i}`);
    const proxyPortElement = document.getElementById(`proxy-port-${i}`);

    if (proxyTypeElement) {
      proxyTypeElement.addEventListener('input', () => {
        saveProxyData(i);
      });
    }

    if (proxyIPElement) {
      proxyIPElement.addEventListener('input', () => {
        saveProxyData(i);
      });
    }

    if (proxyPortElement) {
      proxyPortElement.addEventListener('input', () => {
        saveProxyData(i);
      });
    }
  }
});

// Функция для сохранения данных в chrome.storage
function saveProxyData(profileIndex) {
  const proxyType = document.getElementById(`proxy-type-${profileIndex}`).value;
  const proxyIP = document.getElementById(`proxy-ip-${profileIndex}`).value;
  const proxyPort = document.getElementById(`proxy-port-${profileIndex}`).value;

  chrome.storage.sync.set({
    [`proxyType${profileIndex}`]: proxyType,
    [`proxyIP${profileIndex}`]: proxyIP,
    [`proxyPort${profileIndex}`]: proxyPort
  });
}

// Проверка на корректность IP адреса
function isValidIP(ip) {
  const regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
  return regex.test(ip);
}

// Проверка на корректность порта
function isValidPort(port) {
  const portNumber = parseInt(port, 10);
  return portNumber >= 1 && portNumber <= 65535;
}




Последнее исправление: maxcom (всего исправлений: 1)

P.S. Могут быть неявные ошибки. Но так вроде всё работает.

Proxy
() автор топика
Ответ на: комментарий от ad0c

Зачем, если есть FoxyProxy?

Люблю минимализм. Насколько получилось его добиться... да Бог его знает. Записал на видео результат того, что вышло. Заодно в эту же папку положил и сами файлы, включая *.png

https://disk.yandex.ru/d/0dsNgICN9QAg9g

Времени, конечно, ушло существенно больше, чем это приложение мне сэкономит. Ну, возможно, еще кому такой велосипед понравится.

Proxy
() автор топика
Ответ на: комментарий от ad0c

К тому же, хотелось проверить, сможет ли ChatGPT написать что-то более менее пригодное. В принципе, может. С подсказками, конечно. Особенно, если не заглядывать под капот.

Proxy
() автор топика

На мой взгляд, один из лучших переключателей прокси - iomega switch.

Два недостатка. Первый, диалог настроек писал безумный шляпник.

Второй - неразбериха в магазине. Есть iomega switch и zeromega switch. Приложения одинаковые и явно ничем не отличаются. Непонятно, как так вышло, где апстрим и все такое.

В остальном это отличный функционал. Есть быстрое переключение прокси. Есть спец прокси на правилах, что прям очень здорово, поскольку позволяет использовать для русских ресурсов русский прокси, импортных ресурсов импортный прокси и для всего остального директ. Ничего не переключая, а если что то не работает то прям в менюшке показывает, что не открылось и тут же можно назначить этим урлам особый прокси или директ.

usermod
()
Ответ на: комментарий от usermod

Спасибо, буду знать. Но пока что, для моих целей, это избыточный функционал. Может понадобится в будущем.

Proxy
() автор топика
Ответ на: комментарий от MoldAndLimeHoney

Спасибо! Аутентификацию, я, кстати, не догадался проверить. Подумаю, что с этим делать.

Proxy
() автор топика
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.