From 96ea8af1adb184fd26842974df8d9a4d9e1bf635 Mon Sep 17 00:00:00 2001 From: go0p Date: Tue, 15 Apr 2025 15:51:16 +0800 Subject: [PATCH] fix pac script --- src/components/ProxySwitch/index.tsx | 42 +-- src/entrypoints/options/App.tsx | 377 +++++++++++++++++---------- 2 files changed, 260 insertions(+), 159 deletions(-) diff --git a/src/components/ProxySwitch/index.tsx b/src/components/ProxySwitch/index.tsx index f7ba0b1..5d520d4 100644 --- a/src/components/ProxySwitch/index.tsx +++ b/src/components/ProxySwitch/index.tsx @@ -214,21 +214,33 @@ export const ProxySwitch: React.FC = () => { // 添加自定义代理 if (customProxies.length > 0) { items.push( - ...customProxies.map(proxy => ({ - key: proxy.key, - label: proxy.name, - icon: YAK, - className: `${currentMode === proxy.key ? 'active-item' : ''} menu-id-${proxy.key}`, - })) + ...customProxies.map(proxy => { + // 构建提示信息:显示代理协议、主机和端口 + const tooltipText = proxy.config.proxyType === 'fixed_servers' && proxy.config.host && proxy.config.port + ? `${proxy.config.scheme || 'http'}://${proxy.config.host}:${proxy.config.port}` + : proxy.config.proxyType === 'pac_script' + ? 'PAC脚本代理' + : proxy.config.proxyType === 'auto_detect' + ? '自动检测代理' + : ''; + + return { + key: proxy.key, + label: proxy.name, + icon: YAK, + className: `${currentMode === proxy.key ? 'active-item' : ''} menu-id-${proxy.key}`, + title: tooltipText, // 添加悬停提示 + }; + }) ); items.push({type: 'divider'}); } diff --git a/src/entrypoints/options/App.tsx b/src/entrypoints/options/App.tsx index fd3b6de..d24fb34 100644 --- a/src/entrypoints/options/App.tsx +++ b/src/entrypoints/options/App.tsx @@ -1,12 +1,31 @@ -import React, { useState, useEffect } from 'react'; -import { ConfigProvider, Layout, Typography, List, Button, Form, Input, Select, Space, Card, Divider, Modal } from 'antd'; -import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'; -import { v4 as uuidv4 } from 'uuid'; -import { browser } from 'wxt/browser'; -import type { ProxyConfig } from '../../types/proxy'; -import { getAllProxyConfigs, saveProxyConfig, deleteProxyConfig, enableProxyConfig, getCurrentProxy } from '../../utils/storage'; -import {ContentActionType, ProxyActionType} from '../../types/action'; -import './App.css'; +import React, { useState, useEffect } from "react"; +import { + ConfigProvider, + Layout, + Typography, + List, + Button, + Form, + Input, + Select, + Space, + Card, + Divider, + Modal, +} from "antd"; +import { PlusOutlined, DeleteOutlined } from "@ant-design/icons"; +import { v4 as uuidv4 } from "uuid"; +import { browser } from "wxt/browser"; +import type { ProxyConfig } from "../../types/proxy"; +import { + getAllProxyConfigs, + saveProxyConfig, + deleteProxyConfig, + enableProxyConfig, + getCurrentProxy, +} from "../../utils/storage"; +import { ContentActionType, ProxyActionType } from "../../types/action"; +import "./App.css"; const { Header, Content } = Layout; const { Title } = Typography; @@ -30,7 +49,7 @@ export default function App() { loadProxies(); } }; - + browser.runtime.onMessage.addListener(handleMessage); return () => { browser.runtime.onMessage.removeListener(handleMessage); @@ -41,116 +60,135 @@ export default function App() { try { // 获取所有代理配置 const allConfigs = await getAllProxyConfigs(); - + // 获取当前启用的代理 const currentProxy = await getCurrentProxy(); - const currentProxyId = currentProxy?.id || ''; - + const currentProxyId = currentProxy?.id || ""; + // 检查当前是否为系统代理或直接连接 - const isSystemOrDirect = currentProxyId === 'system' || currentProxyId === 'direct'; - - // 只显示自定义代理服务器配置 - const customProxies = allConfigs.filter(config => config.proxyType === "fixed_servers"); - + const isSystemOrDirect = + currentProxyId === "system" || currentProxyId === "direct"; + + // 显示自定义代理服务器配置和PAC脚本配置 + const customProxies = allConfigs.filter( + (config) => + config.proxyType === "fixed_servers" || + config.proxyType === "pac_script" + ); + // 如果当前是系统代理或直接连接,则所有自定义代理显示为未启用 if (isSystemOrDirect) { - console.log('系统代理或直接连接已启用,确保自定义代理状态正确'); + console.log("系统代理或直接连接已启用,确保自定义代理状态正确"); // 确保UI状态与实际状态一致 - setProxies(customProxies.map(proxy => ({ - ...proxy, - enabled: false - }))); + setProxies( + customProxies.map((proxy) => ({ + ...proxy, + enabled: false, + })) + ); } else { setProxies(customProxies); } } catch (error) { - console.error('Error loading proxies:', error); + console.error("Error loading proxies:", error); } }; const handleSave = async (values: any) => { try { setLoading(true); - + const newProxy: Partial = { id: uuidv4(), name: values.name, - enabled: false + enabled: false, }; - - if (values.proxyType === 'fixed_servers') { - newProxy.proxyType = 'fixed_servers'; + + if (values.proxyType === "fixed_servers") { + newProxy.proxyType = "fixed_servers"; newProxy.scheme = values.scheme; newProxy.host = values.host; newProxy.port = Number(values.port); - + // 处理不经过代理的地址 if (values.bypassList) { newProxy.bypassList = values.bypassList - .split('\n') + .split("\n") .map((line: string) => line.trim()) .filter((line: string) => line.length > 0); } else { newProxy.bypassList = []; } - } else if (values.proxyType === 'pac_script') { - newProxy.proxyType = 'pac_script'; - newProxy.mode = 'pac_script'; - + } else if (values.proxyType === "pac_script") { + newProxy.proxyType = "pac_script"; + newProxy.mode = "pac_script"; + // 处理PAC脚本匹配域名 if (values.matchList) { newProxy.matchList = values.matchList - .split('\n') + .split("\n") .map((line: string) => line.trim()) .filter((line: string) => line.length > 0); } - + + // 解析选择的代理服务器 + const [host, port] = values.proxyServer.split(":"); + // 创建PAC脚本 newProxy.pacScript = { data: `function FindProxyForURL(url, host) { - // 匹配域名列表 - const domains = ${JSON.stringify(newProxy.matchList || [])}; + // Convert host to lowercase for case-insensitive matching + host = host.toLowerCase(); - // 检查是否匹配任何域名 - for (let i = 0; i < domains.length; i++) { - const domain = domains[i]; - // 支持通配符 - if (domain.startsWith('*.') && host.endsWith(domain.substring(1))) { - return 'PROXY ${values.host}:${values.port}'; - } else if (host === domain) { - return 'PROXY ${values.host}:${values.port}'; + // Define domain patterns + var domains = ${JSON.stringify(newProxy.matchList || [])}; + + // Check each domain pattern + for (var i = 0; i < domains.length; i++) { + var pattern = domains[i].toLowerCase(); + + if (pattern.startsWith('*.')) { + var suffix = pattern.substring(2); + if (host === suffix || host.endsWith('.' + suffix)) { + return 'PROXY ${host}:${port}'; + } + } else if (host === pattern) { + return 'PROXY ${host}:${port}'; } } - // 默认直接连接 return 'DIRECT'; }`, - mandatory: true + mandatory: true, }; + + // 保存代理服务器信息 + newProxy.host = host; + newProxy.port = Number(port); } - + // 添加认证信息 if (values.username) newProxy.username = values.username; if (values.password) newProxy.password = values.password; - + await saveProxyConfig(newProxy as ProxyConfig); - + // 重新加载代理列表 await loadProxies(); - + // 重置表单 form.resetFields(); - + // 关闭模态框 setIsModalOpen(false); - + // 通知后台脚本 browser.runtime.sendMessage({ action: ContentActionType.PROXY_CONFIGS_UPDATED, - source: 'options' + source: "options", }); } catch (error) { - console.error('Error saving proxy:', error); + console.error("Error saving proxy:", error); } finally { setLoading(false); } @@ -160,11 +198,11 @@ export default function App() { try { await deleteProxyConfig(id); await loadProxies(); - + // 通知后台脚本 browser.runtime.sendMessage({ action: ContentActionType.PROXY_CONFIGS_UPDATED, - source: 'options' + source: "options", }); } catch (error) { console.error(`Error deleting proxy ${id}:`, error); @@ -175,20 +213,20 @@ export default function App() { try { // 启用代理 await enableProxyConfig(id); - + // 发送切换代理请求 await browser.runtime.sendMessage({ action: ProxyActionType.SWITCH_PROXY, - mode: id + mode: id, }); - + // 重新加载代理列表 await loadProxies(); - + // 通知后台脚本 browser.runtime.sendMessage({ action: ContentActionType.PROXY_CONFIGS_UPDATED, - source: 'options' + source: "options", }); } catch (error) { console.error(`Error activating proxy ${id}:`, error); @@ -214,23 +252,25 @@ export default function App() { >
- Yaklang 代理管理设置 + + Yaklang 代理管理设置 +
- } onClick={showModal} size="small" - style={{ - backgroundColor: "#F28B44", + style={{ + backgroundColor: "#F28B44", borderColor: "#F28B44", borderRadius: "4px", - fontSize: "13px" + fontSize: "13px", }} > 添加代理 @@ -241,44 +281,52 @@ export default function App() { dataSource={proxies} locale={{ emptyText: ( -
+
- No data
-

还没有添加任何代理

+

还没有添加任何代理

- ) + ), }} renderItem={(proxy) => ( handleActivate(proxy.id)} disabled={proxy.enabled} - style={proxy.enabled ? { - backgroundColor: "#F28B44", - color: "white", - borderColor: "#F28B44" - } : undefined} + style={ + proxy.enabled + ? { + backgroundColor: "#F28B44", + color: "white", + borderColor: "#F28B44", + } + : undefined + } > - {proxy.enabled ? '已启用' : '启用'} + {proxy.enabled ? "已启用" : "启用"} , - , - + , ]} destroyOnClose > -
+ 名称} - rules={[{ required: true, message: '请输入代理名称' }]} + rules={[{ required: true, message: "请输入代理名称" }]} > - + 类型} initialValue="fixed_servers" - rules={[{ required: true, message: '请选择代理类型' }]} + rules={[{ required: true, message: "请选择代理类型" }]} > - + prevValues.proxyType !== currentValues.proxyType} + shouldUpdate={(prevValues, currentValues) => + prevValues.proxyType !== currentValues.proxyType + } > {({ getFieldValue }) => { - const proxyType = getFieldValue('proxyType'); - if (proxyType === 'fixed_servers') { + const proxyType = getFieldValue("proxyType"); + if (proxyType === "fixed_servers") { return ( <> 协议} initialValue="http" - rules={[{ required: true, message: '请选择代理协议' }]} + rules={[ + { required: true, message: "请选择代理协议" }, + ]} > - + 主机} - rules={[{ required: true, message: '请输入主机地址' }]} + rules={[ + { required: true, message: "请输入主机地址" }, + ]} > - + 端口} - rules={[{ required: true, message: '请输入端口' }]} + rules={[{ required: true, message: "请输入端口" }]} > - - - + -
每行一个地址,支持通配符 *
+
+ 每行一个地址,支持通配符 * +
+ + + + + + + + + + ); - } else if (proxyType === 'pac_script') { + } else if (proxyType === "pac_script") { return ( <> 匹配域名} - rules={[{ required: true, message: '请输入至少一个匹配域名' }]} + label="匹配域名" + help="每行一个域名,支持通配符 *" + rules={[ + { + required: true, + message: "请输入至少一个匹配域名", + }, + ]} > - -
每行一个域名,支持通配符 *
+
+ + + 选择代理服务器 + + } + rules={[ + { required: true, message: "请选择代理服务器" }, + ]} + > + ); @@ -408,28 +515,10 @@ github.com`} return null; }}
- - - - - - - - - -
); -} \ No newline at end of file +}