LINUX.ORG.RU

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

 ,


1

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
() автор топика

Проверка на корректность IP адреса

Вроде js такой специализированный, неужели в нем нет проверки на валидность IP?

dmitry237 ★★★★
()
Ответ на: комментарий от FatPinguin

О да, вирус. Только на 100% open-source.

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

Могу ошибаться, но вроде только через сторонние библиотеки.

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

manifest.json



{
  "manifest_version": 3,
  "name": "Proxy Settings Extension",
  "version": "1.5",
  "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",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}


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

background.js


// Вспомогательные функции для валидации
function isValidPort(port) {
  const parsedPort = parseInt(port, 10);
  return !isNaN(parsedPort) && parsedPort > 0 && parsedPort <= 65535;
}

function isValidIP(ip) {
  // Простая проверка формата IPv4-адреса
  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);
}

// Инициализация значений по умолчанию при установке расширения
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}`]: '127.0.0.1',
          [`proxyPort${i}`]: '1080'
        });
      }
    });
  }
});

// Обработчик сообщений из popup.js
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}`] || '127.0.0.1';
      const proxyPort = data[`proxyPort${profile}`] || '1080';

      // Дополнительная валидация
      if (!isValidPort(proxyPort)) {
        sendResponse({ success: false, error: 'Invalid proxy port number' });
        return;
      }
      if (!isValidIP(proxyIP)) {
        sendResponse({ success: false, error: 'Invalid proxy IP address' });
        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; // Асинхронный ответ
  }
});


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

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: 700px;
      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;
      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;
    }
    .profile {
      flex: 1 1 170px;
      border: 1px solid #ddd;
      padding: 15px;
      border-radius: 5px;
      margin: 10px;
      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">
    <!-- Профиль 1 -->
    <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="127.0.0.1">

      <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>

    <!-- Профиль 2 -->
    <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="127.0.0.1">

      <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>

    <!-- Профиль 3 -->
    <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="127.0.0.1">

      <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>


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

popup.js



document.addEventListener('DOMContentLoaded', () => {
  // Запрос текущего состояния прокси
  chrome.runtime.sendMessage({ action: 'get-proxy-status' }, (response) => {
    const proxyStatusEl = document.getElementById('proxy-status');
    const disableProxyButton = document.getElementById('disable-proxy');
    
    if (response && response.active) {
      proxyStatusEl.textContent = `Proxy Active (Profile ${response.activeProfile})`;
      disableProxyButton.disabled = false;
    } else {
      proxyStatusEl.textContent = 'Proxy OFF';
      disableProxyButton.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}`] || '127.0.0.1';
        document.getElementById(`proxy-port-${i}`).value = data[`proxyPort${i}`] || '1080';
      });
    }
  });

  // Обработчики для кнопок "Apply Proxy" для каждого профиля
  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
        chrome.storage.sync.set({
          [`proxyType${i}`]: proxyType,
          [`proxyIP${i}`]: proxyIP,
          [`proxyPort${i}`]: proxyPort
        }, () => {
          chrome.runtime.sendMessage({ action: 'apply-proxy', profile: i }, (response) => {
            if (response && 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.`);
    }
  }

  // Обработчик для кнопки "Disable Proxy"
  const disableProxyButton = document.getElementById('disable-proxy');
  if (disableProxyButton) {
    disableProxyButton.addEventListener('click', () => {
      chrome.runtime.sendMessage({ action: 'disable-all-proxies' }, (response) => {
        if (response && response.success) {
          document.getElementById('proxy-status').textContent = 'Proxy OFF';
          disableProxyButton.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('change', () => 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 !isNaN(portNumber) && portNumber >= 1 && portNumber <= 65535;
}


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

Поправил по мелочи. На яндекс диск тоже закинул. Аутентификации как не было, так и нет. И пока не знаю, что с ней делать. Но мне она и не нужна сейчас.

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

никто из сокетописателей этот айпи не проверяет, если неправльный будет введен, то будет ошибка подключения - это лучший вариант чем кривая регулярка и игнорирование существования ipv6

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

минус extensions в том, что они требуют определенную версию веб-браузера. А старые версии extension`а найти сложно.

Впрочем неясно, чем предложенное решение лучше стандартного Proxy auto-config.

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

Не могу сообразить как переключать на лету.

К примеру, Ютуб работает только через анти-DPI, но при этом отваливаются другие сайты, навскидку не вспомню... ну Хабр, как пример.

Не удается получить доступ к сайту
Превышено время ожидания ответа от сайта habr.com.
Попробуйте сделать следующее:

Проверьте подключение к Интернету.
Проверьте настройки прокси-сервера и брандмауэра.
ERR_TIMED_OUT
Proxy
() автор топика
Ответ на: комментарий от pfg

Да это я понимаю. Но, выходит, условия нужно для каждого сайта прописать. А тут хоть всё через прокси, а отдельные напрямую, хоть всё напрямую, а отдельные через прокси... Список сайтов заранее неизвестен. А так, задал поиск, если напрямую не открылось - открыл через прокси, не работает через прокси - открыл напрямую. Сайт может вообще понадобится один раз в жизни, так что, для него правило писать...

Ну или я чего то не разобрал еще... Но разве можно написать правило: «Если сайт замедлен, то через прокси...»?

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

я сразу не понял что твой переключатель делает (т.к. ты просто код положил, а фичи не описал). Если оно с UI, то согласен, что PAC это немного другое.

Лучше бы ты вместо кода написал, что это extension к Google Chrome, фичи, скриншот, способ установки и настройки.

MirandaUser2
()

Описание

Расширение «Proxy Settings Extension» для браузера Chromium позволяет управлять настройками прокси-сервера. Пользователь может выбрать тип прокси, IPv4-адрес и номер порта для различных профилей. Расширение поддерживает три профиля, между которыми можно переключаться, нажимая кнопку «Apply Proxy».

Инструкция по установке и использованию

[1]Установка расширения:

  • Откройте браузер.
  • Перейдите в меню «Настройки» -> «Расширения».
  • Включите «Режим разработчика» в правом верхнем углу.
  • Нажмите на кнопку «Загрузить распакованное расширение» и выберите папку с распакованным расширением.
  • Расширение установлено и готово к использованию.

[2]Добавление значка расширения на панель инструментов:

  • Нажмите на значок пазла в правом верхнем углу браузера.
  • Найдите расширение «Proxy Settings Extension» в списке и нажмите на значок булавки рядом с ним, чтобы закрепить его на панели инструментов.

[3]Использование расширения:

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

[4]Настройка профилей:

  • Тип прокси: Выберите тип прокси (SOCKS5, HTTP, HTTPS).
  • IP-адрес: Введите IP-адрес прокси-сервера.
  • Порт: Введите номер порта.
  • Сохранение: Нажмите «Apply Proxy» для сохранения и применения настроек. Для переключения между профилями, нажимайте «Apply Proxy» для соответствующего профиля.

[5]Отключение прокси:

  • Нажмите «Disable Proxy» для отключения всех настроек прокси.

[6]Статус прокси:

  • Текущий статус прокси отображается в верхней части окна.

В общем, как-то так. Добавил скриншоты на Яндекс диск.

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

Если нужен ipv6:

background.js


// Вспомогательные функции для валидации
function isValidPort(port) {
  const parsedPort = parseInt(port, 10);
  return !isNaN(parsedPort) && parsedPort > 0 && parsedPort <= 65535;
}

/*
// Чтобы снова включить проверку корректности IP адреса, раскомментируйте функцию ниже:
function isValidIP(ip) {
  // Простая проверка формата IPv4-адреса
  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);
}
*/

// Инициализация значений по умолчанию при установке расширения
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}`]: '127.0.0.1',
          [`proxyPort${i}`]: '1080'
        });
      }
    });
  }
});

// Обработчик сообщений из popup.js
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}`] || '127.0.0.1';
      const proxyPort = data[`proxyPort${profile}`] || '1080';

      // Дополнительная валидация
      if (!isValidPort(proxyPort)) {
        sendResponse({ success: false, error: 'Invalid proxy port number' });
        return;
      }
      /*
      // Чтобы снова включить проверку корректности IP адреса, раскомментируйте код ниже:
      if (!isValidIP(proxyIP)) {
        sendResponse({ success: false, error: 'Invalid proxy IP address' });
        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; // Асинхронный ответ
  }
});


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

Если нужен ipv6:

popup.js


document.addEventListener('DOMContentLoaded', () => {
  // Запрос текущего состояния прокси
  chrome.runtime.sendMessage({ action: 'get-proxy-status' }, (response) => {
    const proxyStatusEl = document.getElementById('proxy-status');
    const disableProxyButton = document.getElementById('disable-proxy');
    
    if (response && response.active) {
      proxyStatusEl.textContent = `Proxy Active (Profile ${response.activeProfile})`;
      disableProxyButton.disabled = false;
    } else {
      proxyStatusEl.textContent = 'Proxy OFF';
      disableProxyButton.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}`] || '127.0.0.1';
        document.getElementById(`proxy-port-${i}`).value = data[`proxyPort${i}`] || '1080';
      });
    }
  });

  // Обработчики для кнопок "Apply Proxy" для каждого профиля
  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;
        }
        /*
        // Чтобы снова включить проверку корректности IP адреса, раскомментируйте код ниже:
        if (!isValidIP(proxyIP)) {
          alert('Invalid proxy IP address');
          return;
        }
        */

        // Сохранение настроек в chrome.storage
        chrome.storage.sync.set({
          [`proxyType${i}`]: proxyType,
          [`proxyIP${i}`]: proxyIP,
          [`proxyPort${i}`]: proxyPort
        }, () => {
          chrome.runtime.sendMessage({ action: 'apply-proxy', profile: i }, (response) => {
            if (response && 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.`);
    }
  }

  // Обработчик для кнопки "Disable Proxy"
  const disableProxyButton = document.getElementById('disable-proxy');
  if (disableProxyButton) {
    disableProxyButton.addEventListener('click', () => {
      chrome.runtime.sendMessage({ action: 'disable-all-proxies' }, (response) => {
        if (response && response.success) {
          document.getElementById('proxy-status').textContent = 'Proxy OFF';
          disableProxyButton.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('change', () => 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
  });
}

// Функция для проверки корректности номера порта
function isValidPort(port) {
  const portNumber = parseInt(port, 10);
  return !isNaN(portNumber) && portNumber >= 1 && portNumber <= 65535;
}

/*
// Чтобы снова включить проверку корректности 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);
}
*/


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

Где ссылка хотя-бы на тот же гитхаб? Или сейчас модно копипастой по кускам собирать?

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

Где ссылка хотя-бы на тот же гитхаб? Или сейчас модно копипастой по кускам собирать?

Гитхаба нет. Да и нечего мне пока на нем выкладывать.

Файлами лежит тут:

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

Версия 1.5

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

Для случая, когда нужен IPv6, добавил туда же proxy_v1_5_without_IP_address_validation.zip, по идее должно работать.

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

Ну уже нет возможности отредактировать. :(

А насчет статьи... Мне кажется, что и так несложно найти по тегам и заголовку.

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