From ddc8c9b1cda76dc7ec0379e99aa6d4f94a7c8ccb Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:28:16 +0800 Subject: [PATCH] Add support for custom PAC and proxy script paths Introduces options to specify custom PAC file and system proxy script paths for system proxy settings. Updates configuration models, view models, UI bindings, and logic for Linux/OSX proxy handling and PAC management to use these custom paths if provided. Also adds UI elements and localization for the new settings. --- .../Handler/SysProxy/ProxySettingLinux.cs | 8 +++- .../Handler/SysProxy/ProxySettingOSX.cs | 8 +++- .../Handler/SysProxy/SysProxyHandler.cs | 2 +- v2rayN/ServiceLib/Manager/PacManager.cs | 26 ++++++------ v2rayN/ServiceLib/Models/ConfigItems.cs | 2 + v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 18 ++++++++ v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 6 +++ v2rayN/ServiceLib/Resx/ResUI.fr.resx | 8 +++- v2rayN/ServiceLib/Resx/ResUI.hu.resx | 6 +++ v2rayN/ServiceLib/Resx/ResUI.resx | 6 +++ v2rayN/ServiceLib/Resx/ResUI.ru.resx | 6 +++ v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 6 +++ v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 6 +++ .../ViewModels/OptionSettingViewModel.cs | 6 +++ .../Views/OptionSettingWindow.axaml | 42 +++++++++++++++++++ .../Views/OptionSettingWindow.axaml.cs | 29 +++++++++++++ v2rayN/v2rayN/Views/OptionSettingWindow.xaml | 22 ++++++++++ .../v2rayN/Views/OptionSettingWindow.xaml.cs | 14 +++++++ 18 files changed, 203 insertions(+), 18 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs index 9cac0018..4929c72e 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs @@ -18,7 +18,13 @@ public static class ProxySettingLinux private static async Task ExecCmd(List args) { - var fileName = await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false); + var customSystemProxyScriptPath = AppManager.Instance.Config.SystemProxyItem?.CustomSystemProxyScriptPath; + var fileName = (customSystemProxyScriptPath.IsNotEmpty() && File.Exists(customSystemProxyScriptPath)) + ? customSystemProxyScriptPath + : await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false); + + // TODO: temporarily notify which script is being used + NoticeManager.Instance.SendMessage(fileName); await Utils.GetCliWrapOutput(fileName, args); } diff --git a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs index 88baa5a6..56fbe24d 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs @@ -23,7 +23,13 @@ public static class ProxySettingOSX private static async Task ExecCmd(List args) { - var fileName = await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false); + var customSystemProxyScriptPath = AppManager.Instance.Config.SystemProxyItem?.CustomSystemProxyScriptPath; + var fileName = (customSystemProxyScriptPath.IsNotEmpty() && File.Exists(customSystemProxyScriptPath)) + ? customSystemProxyScriptPath + : await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false); + + // TODO: temporarily notify which script is being used + NoticeManager.Instance.SendMessage(fileName); await Utils.GetCliWrapOutput(fileName, args); } diff --git a/v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs b/v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs index 38ea04ae..426945e0 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs @@ -91,7 +91,7 @@ public static class SysProxyHandler private static async Task SetWindowsProxyPac(int port) { var portPac = AppManager.Instance.GetLocalPort(EInboundProtocol.pac); - await PacManager.Instance.StartAsync(Utils.GetConfigPath(), port, portPac); + await PacManager.Instance.StartAsync(port, portPac); var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}"; ProxySettingWindows.SetProxy(strProxy, "", 4); } diff --git a/v2rayN/ServiceLib/Manager/PacManager.cs b/v2rayN/ServiceLib/Manager/PacManager.cs index cba89830..92c0b5ba 100644 --- a/v2rayN/ServiceLib/Manager/PacManager.cs +++ b/v2rayN/ServiceLib/Manager/PacManager.cs @@ -5,7 +5,6 @@ public class PacManager private static readonly Lazy _instance = new(() => new PacManager()); public static PacManager Instance => _instance.Value; - private string _configPath; private int _httpPort; private int _pacPort; private TcpListener? _tcpListener; @@ -13,11 +12,10 @@ public class PacManager private bool _isRunning; private bool _needRestart = true; - public async Task StartAsync(string configPath, int httpPort, int pacPort) + public async Task StartAsync(int httpPort, int pacPort) { - _needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning; + _needRestart = httpPort != _httpPort || pacPort != _pacPort || !_isRunning; - _configPath = configPath; _httpPort = httpPort; _pacPort = pacPort; @@ -32,22 +30,22 @@ public class PacManager private async Task InitText() { - var path = Path.Combine(_configPath, "pac.txt"); + var customSystemProxyPacPath = AppManager.Instance.Config.SystemProxyItem?.CustomSystemProxyPacPath; + var fileName = (customSystemProxyPacPath.IsNotEmpty() && File.Exists(customSystemProxyPacPath)) + ? customSystemProxyPacPath + : Path.Combine(Utils.GetConfigPath(), "pac.txt"); - // Delete the old pac file - if (File.Exists(path) && Utils.GetFileHash(path).Equals("b590c07280f058ef05d5394aa2f927fe")) - { - File.Delete(path); - } + // TODO: temporarily notify which script is being used + NoticeManager.Instance.SendMessage(fileName); - if (!File.Exists(path)) + if (!File.Exists(fileName)) { var pac = EmbedUtils.GetEmbedText(Global.PacFileName); - await File.AppendAllTextAsync(path, pac); + await File.AppendAllTextAsync(fileName, pac); } - var pacText = - (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;"); + var pacText = await File.ReadAllTextAsync(fileName); + pacText = pacText.Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;"); var sb = new StringBuilder(); sb.AppendLine("HTTP/1.0 200 OK"); diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs index 531a99f4..22b917a6 100644 --- a/v2rayN/ServiceLib/Models/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/ConfigItems.cs @@ -219,6 +219,8 @@ public class SystemProxyItem public string SystemProxyExceptions { get; set; } public bool NotProxyLocalAddress { get; set; } = true; public string SystemProxyAdvancedProtocol { get; set; } + public string? CustomSystemProxyPacPath { get; set; } + public string? CustomSystemProxyScriptPath { get; set; } } [Serializable] diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index b0721398..dca8f3cd 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -3508,6 +3508,24 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Custom PAC file path 的本地化字符串。 + /// + public static string TbSettingsCustomSystemProxyPacPath { + get { + return ResourceManager.GetString("TbSettingsCustomSystemProxyPacPath", resourceCulture); + } + } + + /// + /// 查找类似 Custom system proxy script file path 的本地化字符串。 + /// + public static string TbSettingsCustomSystemProxyScriptPath { + get { + return ResourceManager.GetString("TbSettingsCustomSystemProxyScriptPath", resourceCulture); + } + } + /// /// 查找类似 Allow Insecure 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 17ace05c..299f6f9f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1624,4 +1624,10 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled. Certificate set + + Custom PAC file path + + + Custom system proxy script file path + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx index 877f3420..74335afe 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1621,4 +1621,10 @@ Ne pas utiliser « Obtenir le certificat » si « Autoriser non sécurisé » es Certificat configuré - + + Custom PAC file path + + + Custom system proxy script file path + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index e0052822..dd6a6a63 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1624,4 +1624,10 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled. Certificate set + + Custom PAC file path + + + Custom system proxy script file path + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index b3e31748..a59d068e 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1624,4 +1624,10 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled. Certificate set + + Custom PAC file path + + + Custom system proxy script file path + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index bdd464ef..59176fa3 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1624,4 +1624,10 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled. Certificate set + + Custom PAC file path + + + Custom system proxy script file path + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 0f8ffb10..a58f3c57 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1621,4 +1621,10 @@ 证书已设置 + + 自定义 PAC 文件路径 + + + 自定义系统代理脚本文件路径 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index 5fb6e2f2..e76a044f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1621,4 +1621,10 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled. Certificate set + + 自訂 PAC 檔案路徑 + + + 自訂系統代理程式腳本檔案路徑 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs index 5d4764b8..81f63d00 100644 --- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs @@ -74,6 +74,8 @@ public class OptionSettingViewModel : MyReactiveObject [Reactive] public bool notProxyLocalAddress { get; set; } [Reactive] public string systemProxyAdvancedProtocol { get; set; } [Reactive] public string systemProxyExceptions { get; set; } + [Reactive] public string CustomSystemProxyPacPath { get; set; } + [Reactive] public string CustomSystemProxyScriptPath { get; set; } #endregion System proxy @@ -191,6 +193,8 @@ public class OptionSettingViewModel : MyReactiveObject notProxyLocalAddress = _config.SystemProxyItem.NotProxyLocalAddress; systemProxyAdvancedProtocol = _config.SystemProxyItem.SystemProxyAdvancedProtocol; systemProxyExceptions = _config.SystemProxyItem.SystemProxyExceptions; + CustomSystemProxyPacPath = _config.SystemProxyItem.CustomSystemProxyPacPath; + CustomSystemProxyScriptPath = _config.SystemProxyItem.CustomSystemProxyScriptPath; #endregion System proxy @@ -347,6 +351,8 @@ public class OptionSettingViewModel : MyReactiveObject _config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions; _config.SystemProxyItem.NotProxyLocalAddress = notProxyLocalAddress; _config.SystemProxyItem.SystemProxyAdvancedProtocol = systemProxyAdvancedProtocol; + _config.SystemProxyItem.CustomSystemProxyPacPath = CustomSystemProxyPacPath; + _config.SystemProxyItem.CustomSystemProxyScriptPath = CustomSystemProxyScriptPath; //tun mode _config.TunModeItem.AutoRoute = TunAutoRoute; diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml index 40faf34a..321dba74 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml @@ -674,6 +674,29 @@ + + + + +