添加代理主机的设置,允许代理设置为其他IP(非127.0.0.1) (#2963)
允许下拉选择ip地址(支持IPv6)、localhost、以及当前系统的主机名,同时兼容手工输入
This commit is contained in:
@@ -3,10 +3,17 @@ import { BaseFieldset } from "@/components/base/base-fieldset";
|
||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { getAutotemProxy, getSystemProxy } from "@/services/cmds";
|
||||
import {
|
||||
getAutotemProxy,
|
||||
getNetworkInterfaces,
|
||||
getNetworkInterfacesInfo,
|
||||
getSystemHostname,
|
||||
getSystemProxy,
|
||||
} from "@/services/cmds";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import { EditRounded } from "@mui/icons-material";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
InputAdornment,
|
||||
List,
|
||||
@@ -17,10 +24,16 @@ import {
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { forwardRef, useImperativeHandle, useMemo, useState } from "react";
|
||||
import {
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const DEFAULT_PAC = `function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
return "PROXY %proxy_host%:%mixed-port%; SOCKS5 %proxy_host%:%mixed-port%; DIRECT;";
|
||||
}`;
|
||||
|
||||
/** NO_PROXY validation */
|
||||
@@ -64,6 +77,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editorOpen, setEditorOpen] = useState(false);
|
||||
const { verge, patchVerge } = useVerge();
|
||||
const [hostOptions, setHostOptions] = useState<string[]>([]);
|
||||
|
||||
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
|
||||
const [sysproxy, setSysproxy] = useState<SysProxy>();
|
||||
@@ -79,6 +93,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
use_default_bypass,
|
||||
system_proxy_bypass,
|
||||
proxy_guard_duration,
|
||||
proxy_host,
|
||||
} = verge ?? {};
|
||||
|
||||
const [value, setValue] = useState({
|
||||
@@ -88,6 +103,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
use_default: use_default_bypass ?? true,
|
||||
pac: proxy_auto_config,
|
||||
pac_content: pac_file_content ?? DEFAULT_PAC,
|
||||
proxy_host: proxy_host ?? "127.0.0.1",
|
||||
});
|
||||
|
||||
const defaultBypass = () => {
|
||||
@@ -110,13 +126,74 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
use_default: use_default_bypass ?? true,
|
||||
pac: proxy_auto_config,
|
||||
pac_content: pac_file_content ?? DEFAULT_PAC,
|
||||
proxy_host: proxy_host ?? "127.0.0.1",
|
||||
});
|
||||
getSystemProxy().then((p) => setSysproxy(p));
|
||||
getAutotemProxy().then((p) => setAutoproxy(p));
|
||||
fetchNetworkInterfaces();
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
// 获取网络接口和主机名
|
||||
const fetchNetworkInterfaces = async () => {
|
||||
try {
|
||||
// 获取系统网络接口信息
|
||||
const interfaces = await getNetworkInterfacesInfo();
|
||||
const ipAddresses: string[] = [];
|
||||
|
||||
// 从interfaces中提取IPv4和IPv6地址
|
||||
interfaces.forEach((iface) => {
|
||||
iface.addr.forEach((address) => {
|
||||
if (address.V4 && address.V4.ip) {
|
||||
ipAddresses.push(address.V4.ip);
|
||||
}
|
||||
if (address.V6 && address.V6.ip) {
|
||||
ipAddresses.push(address.V6.ip);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取当前系统的主机名
|
||||
let hostname = "";
|
||||
try {
|
||||
hostname = await getSystemHostname();
|
||||
console.log("获取到主机名:", hostname);
|
||||
} catch (err) {
|
||||
console.error("获取主机名失败:", err);
|
||||
}
|
||||
|
||||
// 构建选项列表
|
||||
const options = ["127.0.0.1", "localhost"];
|
||||
|
||||
// 确保主机名添加到列表,即使它是空字符串也记录下来
|
||||
if (hostname) {
|
||||
// 如果主机名不是localhost或127.0.0.1,则添加它
|
||||
if (hostname !== "localhost" && hostname !== "127.0.0.1") {
|
||||
hostname = hostname + ".local";
|
||||
options.push(hostname);
|
||||
console.log("主机名已添加到选项中:", hostname);
|
||||
} else {
|
||||
console.log("主机名与已有选项重复:", hostname);
|
||||
}
|
||||
} else {
|
||||
console.log("主机名为空");
|
||||
}
|
||||
|
||||
// 添加IP地址
|
||||
options.push(...ipAddresses);
|
||||
|
||||
// 去重
|
||||
const uniqueOptions = Array.from(new Set(options));
|
||||
console.log("最终选项列表:", uniqueOptions);
|
||||
setHostOptions(uniqueOptions);
|
||||
} catch (error) {
|
||||
console.error("获取网络接口失败:", error);
|
||||
// 失败时至少提供基本选项
|
||||
setHostOptions(["127.0.0.1", "localhost"]);
|
||||
}
|
||||
};
|
||||
|
||||
const onSave = useLockFn(async () => {
|
||||
if (value.duration < 1) {
|
||||
Notice.error(t("Proxy Daemon Duration Cannot be Less than 1 Second"));
|
||||
@@ -127,6 +204,23 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 修改验证规则,允许IP和主机名
|
||||
const ipv4Regex =
|
||||
/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
const ipv6Regex =
|
||||
/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
|
||||
const hostnameRegex =
|
||||
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
|
||||
|
||||
if (
|
||||
!ipv4Regex.test(value.proxy_host) &&
|
||||
!ipv6Regex.test(value.proxy_host) &&
|
||||
!hostnameRegex.test(value.proxy_host)
|
||||
) {
|
||||
Notice.error(t("Invalid Proxy Host Format"));
|
||||
return;
|
||||
}
|
||||
|
||||
const patch: Partial<IVergeConfig> = {};
|
||||
|
||||
if (value.guard !== enable_proxy_guard) {
|
||||
@@ -138,15 +232,34 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
if (value.bypass !== system_proxy_bypass) {
|
||||
patch.system_proxy_bypass = value.bypass;
|
||||
}
|
||||
|
||||
if (value.pac !== proxy_auto_config) {
|
||||
patch.proxy_auto_config = value.pac;
|
||||
}
|
||||
if (value.use_default !== use_default_bypass) {
|
||||
patch.use_default_bypass = value.use_default;
|
||||
}
|
||||
if (value.pac_content !== pac_file_content) {
|
||||
patch.pac_file_content = value.pac_content;
|
||||
|
||||
let pacContent = value.pac_content;
|
||||
if (pacContent) {
|
||||
pacContent = pacContent.replace(/%proxy_host%/g, value.proxy_host);
|
||||
}
|
||||
|
||||
if (pacContent !== pac_file_content) {
|
||||
patch.pac_file_content = pacContent;
|
||||
}
|
||||
|
||||
// 处理IPv6地址,如果是IPv6地址但没有被方括号包围,则添加方括号
|
||||
let proxyHost = value.proxy_host;
|
||||
if (
|
||||
ipv6Regex.test(proxyHost) &&
|
||||
!proxyHost.startsWith("[") &&
|
||||
!proxyHost.endsWith("]")
|
||||
) {
|
||||
proxyHost = `[${proxyHost}]`;
|
||||
}
|
||||
|
||||
if (proxyHost !== proxy_host) {
|
||||
patch.proxy_host = proxyHost;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -199,6 +312,31 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
</FlexBox>
|
||||
)}
|
||||
</BaseFieldset>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Proxy Host")} />
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ width: 150 }}
|
||||
options={hostOptions}
|
||||
value={value.proxy_host}
|
||||
freeSolo
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} placeholder="127.0.0.1" size="small" />
|
||||
)}
|
||||
onChange={(_, newValue) => {
|
||||
setValue((v) => ({
|
||||
...v,
|
||||
proxy_host: newValue || "127.0.0.1",
|
||||
}));
|
||||
}}
|
||||
onInputChange={(_, newInputValue) => {
|
||||
setValue((v) => ({
|
||||
...v,
|
||||
proxy_host: newInputValue || "127.0.0.1",
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Use PAC Mode")} />
|
||||
<Switch
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
"Enabled": "ممكّن",
|
||||
"Disabled": "معطّل",
|
||||
"Server Addr": "عنوان الخادم:",
|
||||
"Proxy Host": "مضيف الوكيل",
|
||||
"Invalid Proxy Host Format": "تنسيق مضيف الوكيل غير صالح",
|
||||
"Not available": "غير متوفر",
|
||||
"Proxy Guard": "حماية الوكيل",
|
||||
"Proxy Guard Info": "عند التمكين، يمنع برامج أخرى من تعديل إعدادات وكيل النظام",
|
||||
|
||||
@@ -243,6 +243,8 @@
|
||||
"Enabled": "Enabled",
|
||||
"Disabled": "Disabled",
|
||||
"Server Addr": "Server Addr: ",
|
||||
"Proxy Host": "Proxy Host",
|
||||
"Invalid Proxy Host Format": "Invalid Proxy Host Format",
|
||||
"Not available": "Not available",
|
||||
"Proxy Guard": "Proxy Guard",
|
||||
"Proxy Guard Info": "Enable to prevent other software from modifying the operating system's proxy settings",
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
"Enabled": "توانایی فعال شد",
|
||||
"Disabled": "غیرفعال شد",
|
||||
"Server Addr": "آدرس سرور: ",
|
||||
"Proxy Host": "میزبان پراکسی",
|
||||
"Invalid Proxy Host Format": "فرمت میزبان پراکسی نامعتبر است",
|
||||
"Not available": "غیر فعال شد",
|
||||
"Proxy Guard": "محافظ پراکسی",
|
||||
"Proxy Guard Info": "امکان جلوگیری از نرمافزارهای دیگر از تغییر تنظیمات پروکسی سیستم عامل را فعال کنید",
|
||||
|
||||
@@ -257,6 +257,8 @@
|
||||
"Enabled": "Diaktifkan",
|
||||
"Disabled": "Dinonaktifkan",
|
||||
"Server Addr": "Alamat Server: ",
|
||||
"Proxy Host": "Host Proksi",
|
||||
"Invalid Proxy Host Format": "Format Host Proksi Tidak Valid",
|
||||
"Not available": "Tidak tersedia",
|
||||
"Proxy Guard": "Penjaga Proksi",
|
||||
"Proxy Guard Info": "Aktifkan untuk mencegah perangkat lunak lain mengubah pengaturan proksi sistem operasi",
|
||||
|
||||
@@ -240,6 +240,8 @@
|
||||
"Enabled": "Включено",
|
||||
"Disabled": "Отключено",
|
||||
"Server Addr": "Адрес сервера: ",
|
||||
"Proxy Host": "Хост прокси",
|
||||
"Invalid Proxy Host Format": "Неверный формат хоста прокси",
|
||||
"Not available": "Недоступно",
|
||||
"Proxy Guard": "Proxy Guard",
|
||||
"Proxy Guard Info": "Включите эту функцию чтобы предотвратить изменение настроек прокси-сервера операционной системы другим ПО",
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
"Enabled": "Кушылган",
|
||||
"Disabled": "Сүнгән",
|
||||
"Server Addr": "Сервер адресы",
|
||||
"Proxy Host": "Прокси хосты",
|
||||
"Invalid Proxy Host Format": "Прокси хосты форматы дөрес түгел",
|
||||
"Not available": "Мөмкин түгел",
|
||||
"Proxy Guard": "Прокси саклаучы",
|
||||
"Proxy Guard Info": "Системалы прокси көйләүләрен чит программа үзгәртмәсен өчен шушы функцияне кабызыгыз",
|
||||
|
||||
@@ -243,6 +243,8 @@
|
||||
"Enabled": "已启用",
|
||||
"Disabled": "未启用",
|
||||
"Server Addr": "服务地址:",
|
||||
"Proxy Host": "代理主机",
|
||||
"Invalid Proxy Host Format": "代理主机格式无效",
|
||||
"Not available": "不可用",
|
||||
"Proxy Guard": "系统代理守卫",
|
||||
"Proxy Guard Info": "开启以防止其他软件修改操作系统的代理设置",
|
||||
|
||||
@@ -265,6 +265,10 @@ export async function getNetworkInterfaces() {
|
||||
return invoke<string[]>("get_network_interfaces");
|
||||
}
|
||||
|
||||
export async function getSystemHostname() {
|
||||
return invoke<string>("get_system_hostname");
|
||||
}
|
||||
|
||||
export async function getNetworkInterfacesInfo() {
|
||||
return invoke<INetworkInterface[]>("get_network_interfaces_info");
|
||||
}
|
||||
|
||||
1
src/services/types.d.ts
vendored
1
src/services/types.d.ts
vendored
@@ -749,6 +749,7 @@ interface IVergeConfig {
|
||||
enable_dns_settings?: boolean;
|
||||
proxy_auto_config?: boolean;
|
||||
pac_file_content?: string;
|
||||
proxy_host?: string;
|
||||
enable_random_port?: boolean;
|
||||
verge_mixed_port?: number;
|
||||
verge_socks_port?: number;
|
||||
|
||||
Reference in New Issue
Block a user