Compare commits

...

28 commits

Author SHA1 Message Date
2dust
6fa5ca5aa9 Revert "Fix missing hysteria2 arguments (#7673)"
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
This reverts commit 3f79df21d9.
2025-08-01 12:16:19 +08:00
2dust
1d1f5641eb up 7.13.5 2025-07-31 20:43:00 +08:00
DHR60
3f79df21d9
Fix missing hysteria2 arguments (#7673) 2025-07-31 16:56:39 +08:00
2dust
ac1231ad54 sing-box LAN listening address changed to 0.0.0.0
https://github.com/2dust/v2rayN/discussions/7669
2025-07-30 21:08:37 +08:00
2dust
8662d94ab6 Fixed bug for macos kill_as_sudo 2025-07-30 20:33:51 +08:00
2dust
3d23f3e3a2 Optimized and improved the code
Optimized and improved the code for killing core processes in non-Windows environments. Now uses a shell script for precise processing.
2025-07-30 19:52:45 +08:00
2dust
6715d7dce6 up 7.13.4 2025-07-29 20:44:43 +08:00
2dust
dad35f57d0 Fixed an issue where root processes could not be exited on macOS 2025-07-29 20:23:42 +08:00
2dust
f779e311ed Optimize code and remove unused resources 2025-07-29 19:42:59 +08:00
maximilionus
ce7c41e3ff
Unix platform elevation enhancements v2 (#7658)
* Remove multiple send password actions on Unix elev

* Remove CoreAdminHandler password verification

This is useless since already handled in
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs with
CheckSudoPasswordAsync().

* Disable caching and prompt for sudo call

* Cleanup CoreAdminHandler pwd verify remains

* Migrate sudo opts to initial pwd verification
2025-07-29 19:28:09 +08:00
DHR60
74bb01d044
Improves private IP address detection (#7657) 2025-07-29 19:18:13 +08:00
DHR60
82f9698c0d
Supports IPv6 addresses in profile summary (#7656) 2025-07-29 19:16:50 +08:00
2dust
6911883995 Fixed the issue where process does not accept sudo password input stream for the first time 2025-07-27 14:53:27 +08:00
2dust
47c509faf6 up 7.13.3 2025-07-27 10:59:23 +08:00
2dust
8704942209 Improve sudo password interaction experience 2025-07-27 10:56:58 +08:00
2dust
e8cdc29bb5 Add sudo password verification success message prompt 2025-07-26 20:55:55 +08:00
DHR60
191a7a6574
Fixes Hysteria2 ports (#7649) 2025-07-26 15:07:07 +08:00
2dust
ad5d21db5a Upgrade Downloader package 2025-07-20 15:06:08 +08:00
2dust
569e939492 Optimizing and improving code 2025-07-20 14:16:19 +08:00
2dust
6a17c539d1 up 7.13.2 2025-07-18 20:07:10 +08:00
2dust
f8a4f946e4 Fixed the issue of missing files when updating GeoFiles
https://github.com/2dust/v2rayN/issues/7585
2025-07-18 19:56:18 +08:00
trojan-uma
0715fa85ce
改进 zh-Hans 描述 (#7579)
* 统一 zh-Hans 文字描述的括号

* 改进描述
2025-07-16 20:35:09 +08:00
2dust
1360051f0c Improve and optimize 2025-07-15 20:17:01 +08:00
2dust
42c4f9a6c6 Bug fix
https://github.com/2dust/v2rayN/issues/7582
2025-07-15 18:37:10 +08:00
2dust
11691d0128 up 7.13.1 2025-07-14 16:32:48 +08:00
2dust
26fe9c63a3 Bug fix
https://github.com/2dust/v2rayN/issues/7537
2025-07-14 16:32:10 +08:00
2dust
30cd033b42 up 7.13.0 2025-07-14 13:23:37 +08:00
2dust
e21c0b4d62 The outbound tag of the route rule can enter a config remarks
https://github.com/2dust/v2rayN/issues/7537
2025-07-13 20:25:53 +08:00
52 changed files with 712 additions and 641 deletions

View file

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Version>7.12.7</Version>
<Version>7.13.5</Version>
</PropertyGroup>
<PropertyGroup>

View file

@ -10,7 +10,7 @@
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.2" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.2" />
<PackageVersion Include="CliWrap" Version="3.9.0" />
<PackageVersion Include="Downloader" Version="3.3.4" />
<PackageVersion Include="Downloader" Version="4.0.2" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
@ -18,11 +18,11 @@
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.8" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.8" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.9" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.9" />
<PackageVersion Include="Splat.NLog" Version="15.4.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />

View file

@ -26,7 +26,7 @@ public class DownloaderHelper
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
MaxTryAgainOnFailure = 2,
RequestConfiguration =
{
Headers = headers,
@ -64,7 +64,7 @@ public class DownloaderHelper
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
MaxTryAgainOnFailure = 2,
RequestConfiguration =
{
Timeout= timeout * 1000,
@ -135,7 +135,7 @@ public class DownloaderHelper
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
MaxTryAgainOnFailure = 2,
RequestConfiguration =
{
Timeout= timeout * 1000,

View file

@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
namespace ServiceLib.Common;
public static class StringEx
public static class Extension
{
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{
@ -79,4 +79,9 @@ public static class StringEx
{
return int.TryParse(value, out var result) ? result : defaultValue;
}
public static List<string> AppendEmpty(this IEnumerable<string> source)
{
return source.Concat(new[] { string.Empty }).ToList();
}
}

View file

@ -223,4 +223,28 @@ public static class FileManager
// ignored
}
}
/// <summary>
/// Creates a Linux shell file with the specified contents.
/// </summary>
/// <param name="fileName"></param>
/// <param name="contents"></param>
/// <param name="overwrite"></param>
/// <returns></returns>
public static async Task<string> CreateLinuxShellFile(string fileName, string contents, bool overwrite)
{
var shFilePath = Utils.GetBinConfigPath(fileName);
// Check if the file already exists and if we should overwrite it
if (!overwrite && File.Exists(shFilePath))
{
return shFilePath;
}
File.Delete(shFilePath);
await File.WriteAllTextAsync(shFilePath, contents);
await Utils.SetLinuxChmod(shFilePath);
return shFilePath;
}
}

View file

@ -323,6 +323,14 @@ public class Utils
return text.Replace("", ",").Replace(Environment.NewLine, ",");
}
public static List<string> GetEnumNames<TEnum>() where TEnum : Enum
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Select(e => e.ToString())
.ToList();
}
#endregion
#region
@ -382,13 +390,44 @@ public class Utils
{
if (IPAddress.TryParse(ip, out var address))
{
// Loopback address check (127.0.0.1 for IPv4, ::1 for IPv6)
if (IPAddress.IsLoopback(address))
return true;
var ipBytes = address.GetAddressBytes();
if (ipBytes[0] == 10)
return true;
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168)
return true;
if (address.AddressFamily == AddressFamily.InterNetwork)
{
// IPv4 private address check
if (ipBytes[0] == 10)
return true;
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168)
return true;
}
else if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
// IPv6 private address check
// Link-local address fe80::/10
if (ipBytes[0] == 0xfe && (ipBytes[1] & 0xc0) == 0x80)
return true;
// Unique local address fc00::/7 (typically fd00::/8)
if ((ipBytes[0] & 0xfe) == 0xfc)
return true;
// Private portion in IPv4-mapped addresses ::ffff:0:0/96
if (address.IsIPv4MappedToIPv6)
{
var ipv4Bytes = ipBytes.Skip(12).ToArray();
if (ipv4Bytes[0] == 10)
return true;
if (ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31)
return true;
if (ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168)
return true;
}
}
}
return false;

View file

@ -38,6 +38,8 @@ public class Global
public const string PacFileName = NamespaceSample + "pac";
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
public const string KillAsSudoOSXShellFileName = NamespaceSample + "kill_as_sudo_osx_sh";
public const string KillAsSudoLinuxShellFileName = NamespaceSample + "kill_as_sudo_linux_sh";
public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp";
@ -528,5 +530,12 @@ public class Global
@""
];
public static readonly List<string> OutboundTags =
[
ProxyTag,
DirectTag,
BlockTag
];
#endregion const
}

View file

@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Text;
using CliWrap;
using CliWrap.Buffered;
namespace ServiceLib.Handler;
@ -11,6 +12,7 @@ public class CoreAdminHandler
private Config _config;
private Action<bool, string>? _updateFunc;
private int _linuxSudoPid = -1;
private const string _tag = "CoreAdminHandler";
public async Task Init(Config config, Action<bool, string> updateFunc)
{
@ -20,6 +22,8 @@ public class CoreAdminHandler
}
_config = config;
_updateFunc = updateFunc;
await Task.CompletedTask;
}
private void UpdateFunc(bool notify, string msg)
@ -29,8 +33,11 @@ public class CoreAdminHandler
public async Task<Process?> RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath)
{
StringBuilder sb = new();
sb.AppendLine("#!/bin/bash");
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
sb.AppendLine($"sudo -S {cmdLine}");
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
Process proc = new()
{
@ -44,33 +51,26 @@ public class CoreAdminHandler
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8,
}
};
proc.OutputDataReceived += (sender, e) =>
void dataHandler(object sender, DataReceivedEventArgs e)
{
if (e.Data.IsNotEmpty())
{
UpdateFunc(false, e.Data + Environment.NewLine);
}
};
proc.ErrorDataReceived += (sender, e) =>
{
if (e.Data.IsNotEmpty())
{
UpdateFunc(false, e.Data + Environment.NewLine);
}
};
}
proc.OutputDataReceived += dataHandler;
proc.ErrorDataReceived += dataHandler;
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync();
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
@ -92,35 +92,27 @@ public class CoreAdminHandler
return;
}
var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
try
{
var shellFileName = Utils.IsOSX() ? Global.KillAsSudoOSXShellFileName : Global.KillAsSudoLinuxShellFileName;
var shFilePath = await FileManager.CreateLinuxShellFile("kill_as_sudo.sh", EmbedUtils.GetEmbedText(shellFileName), true);
if (shFilePath.Contains(' '))
{
shFilePath = shFilePath.AppendQuotes();
}
var arg = new List<string>() { "-c", $"sudo -S {shFilePath} {_linuxSudoPid}" };
var result = await Cli.Wrap(Global.LinuxBash)
.WithArguments(arg)
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
.ExecuteBufferedAsync();
await Cli.Wrap(shFilePath)
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
.ExecuteAsync();
UpdateFunc(false, result.StandardOutput.ToString());
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
_linuxSudoPid = -1;
}
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{
var shFilePath = Utils.GetBinConfigPath(fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (Utils.IsAdministrator())
{
sb.AppendLine($"{cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
return shFilePath;
}
}

View file

@ -280,20 +280,15 @@ public class CoreHandler
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
void dataHandler(object sender, DataReceivedEventArgs e)
{
if (e.Data.IsNotEmpty())
{
UpdateFunc(false, e.Data + Environment.NewLine);
}
};
proc.ErrorDataReceived += (sender, e) =>
{
if (e.Data.IsNotEmpty())
{
UpdateFunc(false, e.Data + Environment.NewLine);
}
};
}
proc.OutputDataReceived += dataHandler;
proc.ErrorDataReceived += dataHandler;
}
proc.Start();

View file

@ -24,7 +24,7 @@ public class Hysteria2Fmt : BaseFmt
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
item.Ports = Utils.UrlDecode(query["mport"] ?? "");
return item;
}

View file

@ -18,14 +18,7 @@ public class ProxySettingLinux
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false);
await Utils.GetCliWrapOutput(fileName, args);
}

View file

@ -23,14 +23,7 @@ public class ProxySettingOSX
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false);
await Utils.GetCliWrapOutput(fileName, args);
}

View file

@ -32,7 +32,7 @@ public class ProfileItem : ReactiveObject
public string GetSummary()
{
var summary = $"[{(ConfigType).ToString()}] ";
var arrAddr = Address.Split('.');
var arrAddr = Address.Contains(':') ? Address.Split(':') : Address.Split('.');
var addr = arrAddr.Length switch
{
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",

View file

@ -2202,6 +2202,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Incorrect password, please try again. 的本地化字符串。
/// </summary>
public static string SudoIncorrectPasswordTip {
get {
return ResourceManager.GetString("SudoIncorrectPasswordTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>
@ -2724,6 +2733,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Can fill in the configuration remarks, please make sure it exist and are unique 的本地化字符串。
/// </summary>
public static string TbRuleOutboundTagTip {
get {
return ResourceManager.GetString("TbRuleOutboundTagTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Encryption method (security) 的本地化字符串。
/// </summary>
@ -3184,7 +3202,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart. 的本地化字符串。
/// 查找类似 The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {

View file

@ -1318,7 +1318,7 @@
<value>رمز عبور sudo سیستم</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.</value>
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*حالت xhttp</value>
@ -1392,4 +1392,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL آزمایش اطلاعات اتصال فعلی</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>Incorrect password, please try again.</value>
</data>
</root>

View file

@ -1318,7 +1318,7 @@
<value>Rendszer sudo jelszó</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mód</value>
@ -1392,4 +1392,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>Incorrect password, please try again.</value>
</data>
</root>

View file

@ -1318,7 +1318,7 @@
<value>System sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
@ -1392,4 +1392,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>Incorrect password, please try again.</value>
</data>
</root>

View file

@ -1318,7 +1318,7 @@
<value>Пароль sudo системы</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>Введенный вами пароль не может быть подтвержден, поэтому убедитесь, что вы ввели его правильно. Если приложение не работает должным образом из-за неправильного ввода, то перезапустите его. Пароль не будет сохранен, и вам придется вводить его заново после каждого перезапуска</value>
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*XHTTP-режим</value>
@ -1392,4 +1392,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL для тестирования текущего соединения</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>Incorrect password, please try again.</value>
</data>
</root>

View file

@ -703,7 +703,7 @@
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号 (;) 分隔。</value>
</data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>显示实时速度(需重启)</value>
<value>显示实时速度 (需重启)</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>去重时保留序号较小的项</value>
@ -739,7 +739,7 @@
<value>开机启动 (可能会不成功)</value>
</data>
<data name="TbSettingsStatistics" xml:space="preserve">
<value>启用流量统计(需重启)</value>
<value>启用流量统计 (需重启)</value>
</data>
<data name="TbSettingsSubConvert" xml:space="preserve">
<value>订阅转换网址 (可选)</value>
@ -886,7 +886,7 @@
<value>仅限路由 (routeOnly)</value>
</data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>请勿将代理服务器用于本地Intranet地址</value>
<value>请勿将代理服务器用于本地 (Intranet) 地址</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve">
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
@ -919,7 +919,7 @@
<value>移至订阅分组</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>启用配置文件拖放排序(需重启)</value>
<value>启用配置文件拖放排序 (需重启)</value>
</data>
<data name="TbAutoRefresh" xml:space="preserve">
<value>自动刷新</value>
@ -946,10 +946,10 @@
<value>仅对 tcp/http、ws 协议生效</value>
</data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>当前字体(需重启)</value>
<value>当前字体 (需重启)</value>
</data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>拷贝字体 TTF/TTC 文件到目录 guiFonts重启设置</value>
<value>拷贝字体 TTF/TTC 文件到目录 guiFonts重启生效</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>Pac 端口 = +3Xray API 端口 = +4mihomo API 端口 = +5</value>
@ -979,10 +979,10 @@
<value>SpiderX</value>
</data>
<data name="TbSettingsEnableHWA" xml:space="preserve">
<value>启用硬件加速(需重启)</value>
<value>启用硬件加速 (需重启)</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>等待测试中(按 ESC 终止)...</value>
<value>等待测试中 (按 ESC 终止)...</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>当有异常断流时请关闭</value>
@ -1075,7 +1075,7 @@
<value>Reserved (2,3,4)</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address (Ipv4,Ipv6)</value>
<value>Address (IPv4,IPv6)</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>混淆密码 (obfs password)</value>
@ -1105,10 +1105,10 @@
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>启用分片Fragment</value>
<value>启用分片 (Fragment)</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>启用 sing-box(规则集文件)的缓存文件</value>
<value>启用 sing-box (规则集文件) 的缓存文件</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>自定义 sing-box rule-set</value>
@ -1201,7 +1201,7 @@
<value>Outbound 默认解析策略</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>主界面布局方向(需重启)</value>
<value>主界面布局方向 (需重启)</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound 域名解析地址</value>
@ -1303,7 +1303,7 @@
<value>请不要使用不安全的 HTTP 协议订阅地址</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安装字体到系统中,选择或填入字体名称,重启设置</value>
<value>安装字体到系统中,选择或填入字体名称,重启生效</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>是否确定退出?</value>
@ -1315,10 +1315,10 @@
<value>系统的 sudo 密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
<value>密码将调用命令行校验,如果因为校验错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
<value>*XHTTP 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
@ -1339,7 +1339,7 @@
<value>开启第二个本地监听端口</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks本地端口socks2第二个本地端口socks3局域网端口</value>
<value>Socks本地端口Socks2第二个本地端口Socks3局域网端口</value>
</data>
<data name="TbSettingsTheme" xml:space="preserve">
<value>主题</value>
@ -1372,13 +1372,13 @@
<value>多配置文件随机 Xray</value>
</data>
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
<value>多配置文件负载均衡  Xray</value>
<value>多配置文件负载均衡 Xray</value>
</data>
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
<value>多配置文件最低延迟  Xray</value>
<value>多配置文件最低延迟 Xray</value>
</data>
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
<value>多配置文件最稳定  Xray</value>
<value>多配置文件最稳定 Xray</value>
</data>
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
<value>多配置文件最低延迟 sing-box</value>
@ -1389,4 +1389,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>当前连接信息测试地址</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>可以填写配置文件别名,请确保存在并唯一</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>密码错误,请重试。</value>
</data>
</root>

View file

@ -1315,7 +1315,7 @@
<value>系統的 sudo 密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會儲存,每次重啟後都需要再次輸入。</value>
<value>密碼將調用命令行校驗,如果因為校驗錯誤導致無法正常運行時,請重啟本應用。密碼不會存儲,每次重啟後都需要再次輸入。</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
@ -1389,4 +1389,10 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>目前連接資訊測試地址</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>可以填寫設定檔別名,請確保存在並唯一</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>密碼錯誤,請重試。</value>
</data>
</root>

View file

@ -0,0 +1,61 @@
#!/bin/bash
#
# Process Terminator Script for Linux
# This script forcibly terminates a process and all its child processes
#
# Check if PID argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <PID>"
exit 1
fi
PID=$1
# Validate that input is a valid PID (numeric)
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
echo "Error: The PID must be a numeric value"
exit 1
fi
# Check if the process exists
if ! ps -p $PID > /dev/null; then
echo "Warning: No process found with PID $PID"
exit 0
fi
# Recursive function to find and kill all child processes
kill_children() {
local parent=$1
local children=$(ps -o pid --no-headers --ppid "$parent")
# Output information about processes being terminated
echo "Processing children of PID: $parent..."
# Process each child
for child in $children; do
# Recursively find and kill child's children first
kill_children "$child"
# Force kill the child process
echo "Terminating child process: $child"
kill -9 "$child" 2>/dev/null || true
done
}
echo "============================================"
echo "Starting termination of process $PID and all its children"
echo "============================================"
# Find and kill all child processes
kill_children "$PID"
# Finally kill the main process
echo "Terminating main process: $PID"
kill -9 "$PID" 2>/dev/null || true
echo "============================================"
echo "Process $PID and all its children have been terminated"
echo "============================================"
exit 0

View file

@ -0,0 +1,56 @@
#!/bin/bash
#
# Process Terminator Script for macOS
# This script forcibly terminates a process and all its descendant processes
#
# Check if PID argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <PID>"
exit 1
fi
PID=$1
# Validate that input is a valid PID (numeric)
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
echo "Error: The PID must be a numeric value"
exit 1
fi
# Check if the process exists - using kill -0 which is more reliable on macOS
if ! kill -0 $PID 2>/dev/null; then
echo "Warning: No process found with PID $PID"
exit 0
fi
# Recursive function to find and kill all descendant processes
kill_descendants() {
local parent=$1
# Use ps -axo for macOS to ensure all processes are included
local children=$(ps -axo pid=,ppid= | awk -v ppid=$parent '$2==ppid {print $1}')
echo "Processing children of PID: $parent..."
for child in $children; do
kill_descendants "$child"
echo "Terminating child process: $child"
kill -9 "$child" 2>/dev/null || true
done
}
echo "============================================"
echo "Starting termination of process $PID and all its descendants"
echo "============================================"
# Find and kill all descendant processes
kill_descendants "$PID"
# Finally kill the main process
echo "Terminating main process: $PID"
kill -9 "$PID" 2>/dev/null || true
echo "============================================"
echo "Process $PID and all its descendants have been terminated"
echo "============================================"
exit 0

View file

@ -28,6 +28,8 @@
<EmbeddedResource Include="Sample\custom_routing_white" />
<EmbeddedResource Include="Sample\dns_singbox_normal" />
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
<EmbeddedResource Include="Sample\kill_as_sudo_linux_sh" />
<EmbeddedResource Include="Sample\kill_as_sudo_osx_sh" />
<EmbeddedResource Include="Sample\pac" />
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />

View file

@ -519,7 +519,7 @@ public class CoreConfigSingboxService
{
try
{
var listen = "::";
var listen = "0.0.0.0";
singboxConfig.inbounds = [];
if (!_config.TunModeItem.EnableTun
@ -706,12 +706,17 @@ public class CoreConfigSingboxService
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
if (node.Ports.IsNotEmpty())
if (node.Ports.IsNotEmpty() && (node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(',')))
{
outbound.server_port = null;
outbound.server_ports = node.Ports.Split(',')
.Where(p => p.Trim().IsNotEmpty())
.Select(p => p.Replace('-', ':'))
.Select(p => p.Trim())
.Where(p => p.IsNotEmpty())
.Select(p =>
{
var port = p.Replace('-', ':');
return port.Contains(':') ? port : $"{port}:{port}";
})
.ToList();
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
}
@ -1166,7 +1171,7 @@ public class CoreConfigSingboxService
{
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
await GenRoutingUserRule(item, singboxConfig);
}
}
}
@ -1206,7 +1211,7 @@ public class CoreConfigSingboxService
lstDirectExe = new List<string>(directExeSet);
}
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
private async Task<int> GenRoutingUserRule(RulesItem item, SingboxConfig singboxConfig)
{
try
{
@ -1214,6 +1219,8 @@ public class CoreConfigSingboxService
{
return 0;
}
item.OutboundTag = await GenRoutingUserRuleOutbound(item.OutboundTag, singboxConfig);
var rules = singboxConfig.route.rules;
var rule = new Rule4Sbox()
{
@ -1365,6 +1372,29 @@ public class CoreConfigSingboxService
return true;
}
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, SingboxConfig singboxConfig)
{
if (Global.OutboundTags.Contains(outboundTag))
{
return outboundTag;
}
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
if (node == null
|| node.ConfigType == EConfigType.Custom)
{
return Global.ProxyTag;
}
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(node, outbound);
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
singboxConfig.outbounds.Add(outbound);
return outbound.tag;
}
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
{
try

View file

@ -54,12 +54,12 @@ public class CoreConfigV2rayService
await GenInbounds(v2rayConfig);
await GenRouting(v2rayConfig);
await GenOutbound(node, v2rayConfig.outbounds.First());
await GenMoreOutbounds(node, v2rayConfig);
await GenRouting(v2rayConfig);
await GenDns(node, v2rayConfig);
await GenStatistic(v2rayConfig);
@ -556,6 +556,8 @@ public class CoreConfigV2rayService
{
return 0;
}
rule.outboundTag = await GenRoutingUserRuleOutbound(rule.outboundTag, v2rayConfig);
if (rule.port.IsNullOrEmpty())
{
rule.port = null;
@ -627,6 +629,31 @@ public class CoreConfigV2rayService
return await Task.FromResult(0);
}
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, V2rayConfig v2rayConfig)
{
if (Global.OutboundTags.Contains(outboundTag))
{
return outboundTag;
}
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
if (node == null
|| node.ConfigType == EConfigType.Custom
|| node.ConfigType == EConfigType.Hysteria2
|| node.ConfigType == EConfigType.TUIC)
{
return Global.ProxyTag;
}
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(node, outbound);
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
v2rayConfig.outbounds.Add(outbound);
return outbound.tag;
}
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
{
try
@ -659,7 +686,7 @@ public class CoreConfigV2rayService
{
usersItem = vnextItem.users.First();
}
usersItem.id = node.Id;
usersItem.alterId = node.AlterId;
usersItem.email = Global.UserEMail;
@ -1318,7 +1345,7 @@ public class CoreConfigV2rayService
//Previous proxy
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
string? prevOutboundTag = null;
string? prevOutboundTag = null;
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2

View file

@ -536,6 +536,11 @@ public class UpdateService
}
}
//append dns items TODO
geoSiteFiles.Add("cn");
geoSiteFiles.Add("geolocation-cn");
geoSiteFiles.Add("category-ads-all");
var path = Utils.GetBinPath("srss");
if (!Directory.Exists(path))
{

View file

@ -436,30 +436,34 @@ public class StatusBarViewModel : MyReactiveObject
private async Task DoEnableTun(bool c)
{
if (_config.TunModeItem.EnableTun != EnableTun)
if (_config.TunModeItem.EnableTun == EnableTun)
{
return;
}
_config.TunModeItem.EnableTun = EnableTun;
if (EnableTun && AllowEnableTun() == false)
{
_config.TunModeItem.EnableTun = EnableTun;
// When running as a non-administrator, reboot to administrator mode
if (EnableTun && AllowEnableTun() == false)
if (Utils.IsWindows())
{
if (Utils.IsWindows())
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
else
{
bool? passwordResult = await _updateView?.Invoke(EViewAction.PasswordInput, null);
if (passwordResult == false)
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
else
{
if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
{
_config.TunModeItem.EnableTun = false;
return;
}
}
}
await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
private bool AllowEnableTun()

View file

@ -61,11 +61,7 @@ internal class Program
//.WithInterFont()
.WithFontByDefault()
.LogToTrace()
#if OS_OSX
.UseReactiveUI()
.With(new MacOSPlatformOptions { ShowInDock = AppHandler.Instance.Config.UiItem.MacOSShowInDock });
#else
.UseReactiveUI();
#endif
}
}

View file

@ -21,13 +21,7 @@ public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
btnCancel.Click += (s, e) => this.Close();
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
{
if (it == ECoreType.v2rayN)
continue;
cmbCoreType.Items.Add(it.ToString());
}
cmbCoreType.Items.Add(string.Empty);
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
this.WhenActivated(disposables =>
{

View file

@ -26,41 +26,22 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
Global.CoreTypes.ForEach(it =>
{
cmbCoreType.Items.Add(it);
});
cmbCoreType.Items.Add(string.Empty);
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
cmbNetwork.ItemsSource = Global.Networks;
cmbFingerprint.ItemsSource = Global.Fingerprints;
cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns;
cmbStreamSecurity.Items.Add(string.Empty);
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
Global.Networks.ForEach(it =>
{
cmbNetwork.Items.Add(it);
});
Global.Fingerprints.ForEach(it =>
{
cmbFingerprint.Items.Add(it);
cmbFingerprint2.Items.Add(it);
});
Global.AllowInsecure.ForEach(it =>
{
cmbAllowInsecure.Items.Add(it);
});
Global.Alpns.ForEach(it =>
{
cmbAlpn.Items.Add(it);
});
var lstStreamSecurity = new List<string>();
lstStreamSecurity.Add(string.Empty);
lstStreamSecurity.Add(Global.StreamSecurity);
switch (profileItem.ConfigType)
{
case EConfigType.VMess:
gridVMess.IsVisible = true;
Global.VmessSecurities.ForEach(it =>
{
cmbSecurity.Items.Add(it);
});
cmbSecurity.ItemsSource = Global.VmessSecurities;
if (profileItem.Security.IsNullOrEmpty())
{
profileItem.Security = Global.DefaultSecurity;
@ -69,10 +50,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Shadowsocks:
gridSs.IsVisible = true;
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
{
cmbSecurity3.Items.Add(it);
});
cmbSecurity3.ItemsSource = AppHandler.Instance.GetShadowsocksSecurities(profileItem);
break;
case EConfigType.SOCKS:
@ -82,11 +60,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.VLESS:
gridVLESS.IsVisible = true;
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.Flows.ForEach(it =>
{
cmbFlow5.Items.Add(it);
});
lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbFlow5.ItemsSource = Global.Flows;
if (profileItem.Security.IsNullOrEmpty())
{
profileItem.Security = Global.None;
@ -95,11 +70,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Trojan:
gridTrojan.IsVisible = true;
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.Flows.ForEach(it =>
{
cmbFlow6.Items.Add(it);
});
lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbFlow6.ItemsSource = Global.Flows;
break;
case EConfigType.Hysteria2:
@ -119,10 +91,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbFingerprint.IsEnabled = false;
cmbFingerprint.SelectedValue = string.Empty;
Global.TuicCongestionControls.ForEach(it =>
{
cmbHeaderType8.Items.Add(it);
});
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
break;
case EConfigType.WireGuard:
@ -134,6 +103,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
break;
}
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
gridTlsMore.IsVisible = false;
@ -272,44 +242,41 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
private void SetHeaderType()
{
cmbHeaderType.Items.Clear();
var lstHeaderType = new List<string>();
var network = cmbNetwork.SelectedItem.ToString();
if (network.IsNullOrEmpty())
{
cmbHeaderType.Items.Add(Global.None);
lstHeaderType.Add(Global.None);
cmbHeaderType.ItemsSource = lstHeaderType;
cmbHeaderType.SelectedIndex = 0;
return;
}
if (network == nameof(ETransport.tcp))
{
cmbHeaderType.Items.Add(Global.None);
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
lstHeaderType.Add(Global.None);
lstHeaderType.Add(Global.TcpHeaderHttp);
}
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
{
cmbHeaderType.Items.Add(Global.None);
Global.KcpHeaderTypes.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
lstHeaderType.Add(Global.None);
lstHeaderType.AddRange(Global.KcpHeaderTypes);
}
else if (network is nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
lstHeaderType.AddRange(Global.XhttpMode);
}
else if (network == nameof(ETransport.grpc))
{
cmbHeaderType.Items.Add(Global.GrpcGunMode);
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
lstHeaderType.Add(Global.GrpcGunMode);
lstHeaderType.Add(Global.GrpcMultiMode);
}
else
{
cmbHeaderType.Items.Add(Global.None);
lstHeaderType.Add(Global.None);
}
cmbHeaderType.ItemsSource = lstHeaderType;
cmbHeaderType.SelectedIndex = 0;
}

View file

@ -17,22 +17,10 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
btnCancel.Click += (s, e) => this.Close();
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
Global.DomainStrategy4Freedoms.ForEach(it =>
{
cmbdomainStrategy4Freedom.Items.Add(it);
});
Global.SingboxDomainStrategy4Out.ForEach(it =>
{
cmbdomainStrategy4Out.Items.Add(it);
});
Global.DomainDNSAddress.ForEach(it =>
{
cmbdomainDNSAddress.Items.Add(it);
});
Global.SingboxDomainDNSAddress.ForEach(it =>
{
cmbdomainDNSAddress2.Items.Add(it);
});
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
this.WhenActivated(disposables =>
{

View file

@ -134,7 +134,6 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
break;
}
});
if (Utils.IsWindows())
{

View file

@ -19,87 +19,39 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
Global.destOverrideProtocols.ForEach(it =>
{
clbdestOverride.Items.Add(it);
});
clbdestOverride.ItemsSource = Global.destOverrideProtocols;
_config.Inbound.First().DestOverride?.ForEach(it =>
{
clbdestOverride.SelectedItems.Add(it);
});
Global.IEProxyProtocols.ForEach(it =>
{
cmbsystemProxyAdvancedProtocol.Items.Add(it);
});
Global.LogLevels.ForEach(it =>
{
cmbloglevel.Items.Add(it);
});
Global.Fingerprints.ForEach(it =>
{
cmbdefFingerprint.Items.Add(it);
});
Global.UserAgent.ForEach(it =>
{
cmbdefUserAgent.Items.Add(it);
});
Global.SingboxMuxs.ForEach(it =>
{
cmbmux4SboxProtocol.Items.Add(it);
});
Global.TunMtus.ForEach(it =>
{
cmbMtu.Items.Add(it);
});
Global.TunStacks.ForEach(it =>
{
cmbStack.Items.Add(it);
});
Global.CoreTypes.ForEach(it =>
{
cmbCoreType1.Items.Add(it);
cmbCoreType2.Items.Add(it);
cmbCoreType3.Items.Add(it);
cmbCoreType4.Items.Add(it);
cmbCoreType5.Items.Add(it);
cmbCoreType6.Items.Add(it);
cmbCoreType9.Items.Add(it);
});
cmbsystemProxyAdvancedProtocol.ItemsSource = Global.IEProxyProtocols;
cmbloglevel.ItemsSource = Global.LogLevels;
cmbdefFingerprint.ItemsSource = Global.Fingerprints;
cmbdefUserAgent.ItemsSource = Global.UserAgent;
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
cmbMtu.ItemsSource = Global.TunMtus;
cmbStack.ItemsSource = Global.TunStacks;
for (var i = 2; i <= 8; i++)
{
cmbMixedConcurrencyCount.Items.Add(i);
}
for (var i = 2; i <= 6; i++)
{
cmbSpeedTestTimeout.Items.Add(i * 5);
}
cmbCoreType1.ItemsSource = Global.CoreTypes;
cmbCoreType2.ItemsSource = Global.CoreTypes;
cmbCoreType3.ItemsSource = Global.CoreTypes;
cmbCoreType4.ItemsSource = Global.CoreTypes;
cmbCoreType5.ItemsSource = Global.CoreTypes;
cmbCoreType6.ItemsSource = Global.CoreTypes;
cmbCoreType9.ItemsSource = Global.CoreTypes;
cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(2, 7).ToList();
cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList();
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
cmbGetFilesSourceUrl.ItemsSource = Global.GeoFilesSources;
cmbSrsFilesSourceUrl.ItemsSource = Global.SingboxRulesetSources;
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
Global.GeoFilesSources.ForEach(it =>
{
cmbGetFilesSourceUrl.Items.Add(it);
});
Global.SingboxRulesetSources.ForEach(it =>
{
cmbSrsFilesSourceUrl.Items.Add(it);
});
Global.RoutingRulesSources.ForEach(it =>
{
cmbRoutingRulesSourceUrl.Items.Add(it);
});
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{
cmbMainGirdOrientation.Items.Add(it.ToString());
}
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
this.WhenActivated(disposables =>
{

View file

@ -2,6 +2,7 @@
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
@ -22,86 +23,95 @@
<TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.LvRemarks}" />
<TextBox
x:Name="txtRemarks"
Grid.Row="0"
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" />
Width="300"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<ToggleSwitch
x:Name="togEnabled"
Grid.Row="0"
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" />
VerticalAlignment="Center" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="outboundTag" />
<ComboBox
x:Name="cmbOutboundTag"
<ctrls:AutoCompleteBox
Name="cmbOutboundTag"
Grid.Row="1"
Grid.Column="1"
Width="200"
Width="300"
Margin="{StaticResource Margin4}"
MaxDropDownHeight="1000" />
Text="{Binding SelectedSource.OutboundTag, Mode=TwoWay}" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="port" />
<TextBox
x:Name="txtPort"
Grid.Row="2"
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" />
Width="300"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}">
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="protocol" />
<ListBox
x:Name="clbProtocol"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
SelectionMode="Multiple,Toggle"
Theme="{DynamicResource CardCheckGroupListBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
</HyperlinkButton>
</TextBlock>
<TextBlock
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
Text="protocol" />
<ListBox
x:Name="clbProtocol"
Grid.Row="3"
Grid.Column="1"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}"
SelectionMode="Multiple,Toggle"
Theme="{DynamicResource CardCheckGroupListBox}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="inboundTag" />
<ListBox
x:Name="clbInboundTag"
@ -113,35 +123,36 @@
<TextBlock
Grid.Row="4"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="network" />
<ComboBox
x:Name="cmbNetwork"
Grid.Row="5"
Grid.Column="1"
Width="200"
Width="300"
Margin="{StaticResource Margin4}"
MaxDropDownHeight="1000" />
<TextBlock
Grid.Row="5"
Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRoutingTips}" />
</Grid>
<StackPanel
HorizontalAlignment="Right"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Right"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<StackPanel

View file

@ -23,21 +23,11 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
cmbOutboundTag.Items.Add(Global.ProxyTag);
cmbOutboundTag.Items.Add(Global.DirectTag);
cmbOutboundTag.Items.Add(Global.BlockTag);
Global.RuleProtocols.ForEach(it =>
{
clbProtocol.Items.Add(it);
});
Global.InboundTags.ForEach(it =>
{
clbInboundTag.Items.Add(it);
});
Global.RuleNetworks.ForEach(it =>
{
cmbNetwork.Items.Add(it);
});
cmbOutboundTag.ItemsSource = Global.OutboundTags;
clbProtocol.ItemsSource = Global.RuleProtocols;
clbInboundTag.ItemsSource = Global.InboundTags;
cmbNetwork.ItemsSource = Global.RuleNetworks;
if (!rulesItem.Id.IsNullOrEmpty())
{
@ -54,7 +44,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
@ -80,7 +70,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
private void Window_Loaded(object? sender, RoutedEventArgs e)
{
cmbOutboundTag.Focus();
txtRemarks.Focus();
}
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)

View file

@ -30,15 +30,9 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
Global.DomainStrategies.ForEach(it =>
{
cmbdomainStrategy.Items.Add(it);
});
cmbdomainStrategy.Items.Add(string.Empty);
Global.DomainStrategies4Singbox.ForEach(it =>
{
cmbdomainStrategy4Singbox.Items.Add(it);
});
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
{

View file

@ -26,18 +26,9 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
Global.DomainStrategies.ForEach(it =>
{
cmbdomainStrategy.Items.Add(it);
});
Global.DomainMatchers.ForEach(it =>
{
cmbdomainMatcher.Items.Add(it);
});
Global.DomainStrategies4Singbox.ForEach(it =>
{
cmbdomainStrategy4Singbox.Items.Add(it);
});
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
{

View file

@ -104,13 +104,15 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
{
var dialog = new SudoPasswordInputView();
var obj = await DialogHost.Show(dialog);
if (obj == null)
var password = obj?.ToString();
if (password.IsNullOrEmpty())
{
togEnableTun.IsChecked = false;
return false;
}
AppHandler.Instance.LinuxSudoPwd = obj.ToString() ?? string.Empty;
AppHandler.Instance.LinuxSudoPwd = password;
return true;
}

View file

@ -22,10 +22,7 @@ public partial class SubEditWindow : WindowBase<SubEditViewModel>
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
Global.SubConvertTargets.ForEach(it =>
{
cmbConvertTarget.Items.Add(it);
});
cmbConvertTarget.ItemsSource = Global.SubConvertTargets;
this.WhenActivated(disposables =>
{

View file

@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Threading;
using CliWrap.Buffered;
using DialogHostAvalonia;
namespace v2rayN.Desktop.Views;
@ -12,22 +13,70 @@ public partial class SudoPasswordInputView : UserControl
this.Loaded += (s, e) => txtPassword.Focus();
btnSave.Click += (_, _) =>
{
if (string.IsNullOrEmpty(txtPassword.Text))
{
txtPassword.Focus();
return;
}
Dispatcher.UIThread.Post(() =>
{
DialogHost.Close(null, txtPassword.Text);
});
};
btnSave.Click += async (_, _) => await SavePasswordAsync();
btnCancel.Click += (_, _) =>
{
DialogHost.Close(null);
};
}
private async Task SavePasswordAsync()
{
if (txtPassword.Text.IsNullOrEmpty())
{
txtPassword.Focus();
return;
}
var password = txtPassword.Text;
btnSave.IsEnabled = false;
try
{
// Verify if the password is correct
if (await CheckSudoPasswordAsync(password))
{
// Password verification successful, return password and close dialog
await Dispatcher.UIThread.InvokeAsync(() =>
{
DialogHost.Close(null, password);
});
}
else
{
// Password verification failed, display error and let user try again
NoticeHandler.Instance.Enqueue(ResUI.SudoIncorrectPasswordTip);
txtPassword.Focus();
}
}
catch (Exception ex)
{
Logging.SaveLog("SudoPassword", ex);
}
finally
{
btnSave.IsEnabled = true;
}
}
private async Task<bool> CheckSudoPasswordAsync(string password)
{
try
{
// Use sudo echo command to verify password
var arg = new List<string>() { "-c", "sudo -S echo SUDO_CHECK" };
var result = await CliWrap.Cli.Wrap(Global.LinuxBash)
.WithArguments(arg)
.WithStandardInputPipe(CliWrap.PipeSource.FromString(password))
.ExecuteBufferedAsync();
return result.ExitCode == 0;
}
catch (Exception ex)
{
Logging.SaveLog("CheckSudoPassword", ex);
return false;
}
}
}

View file

@ -16,20 +16,9 @@ public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewMode
InitializeComponent();
ViewModel = new ThemeSettingViewModel();
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
{
cmbCurrentTheme.Items.Add(it.ToString());
}
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
{
cmbCurrentFontSize.Items.Add(i);
}
Global.Languages.ForEach(it =>
{
cmbCurrentLanguage.Items.Add(it);
});
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>();
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList();
cmbCurrentLanguage.ItemsSource = Global.Languages;
this.WhenActivated(disposables =>
{

View file

@ -14,13 +14,7 @@ public partial class AddServer2Window
this.Loaded += Window_Loaded;
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
{
if (it == ECoreType.v2rayN)
continue;
cmbCoreType.Items.Add(it.ToString());
}
cmbCoreType.Items.Add(string.Empty);
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
this.WhenActivated(disposables =>
{

View file

@ -20,41 +20,22 @@ public partial class AddServerWindow
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
Global.CoreTypes.ForEach(it =>
{
cmbCoreType.Items.Add(it);
});
cmbCoreType.Items.Add(string.Empty);
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
cmbNetwork.ItemsSource = Global.Networks;
cmbFingerprint.ItemsSource = Global.Fingerprints;
cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns;
cmbStreamSecurity.Items.Add(string.Empty);
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
Global.Networks.ForEach(it =>
{
cmbNetwork.Items.Add(it);
});
Global.Fingerprints.ForEach(it =>
{
cmbFingerprint.Items.Add(it);
cmbFingerprint2.Items.Add(it);
});
Global.AllowInsecure.ForEach(it =>
{
cmbAllowInsecure.Items.Add(it);
});
Global.Alpns.ForEach(it =>
{
cmbAlpn.Items.Add(it);
});
var lstStreamSecurity = new List<string>();
lstStreamSecurity.Add(string.Empty);
lstStreamSecurity.Add(Global.StreamSecurity);
switch (profileItem.ConfigType)
{
case EConfigType.VMess:
gridVMess.Visibility = Visibility.Visible;
Global.VmessSecurities.ForEach(it =>
{
cmbSecurity.Items.Add(it);
});
cmbSecurity.ItemsSource = Global.VmessSecurities;
if (profileItem.Security.IsNullOrEmpty())
{
profileItem.Security = Global.DefaultSecurity;
@ -63,10 +44,7 @@ public partial class AddServerWindow
case EConfigType.Shadowsocks:
gridSs.Visibility = Visibility.Visible;
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
{
cmbSecurity3.Items.Add(it);
});
cmbSecurity3.ItemsSource = AppHandler.Instance.GetShadowsocksSecurities(profileItem);
break;
case EConfigType.SOCKS:
@ -76,11 +54,8 @@ public partial class AddServerWindow
case EConfigType.VLESS:
gridVLESS.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.Flows.ForEach(it =>
{
cmbFlow5.Items.Add(it);
});
lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbFlow5.ItemsSource = Global.Flows;
if (profileItem.Security.IsNullOrEmpty())
{
profileItem.Security = Global.None;
@ -89,11 +64,8 @@ public partial class AddServerWindow
case EConfigType.Trojan:
gridTrojan.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.Flows.ForEach(it =>
{
cmbFlow6.Items.Add(it);
});
lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbFlow6.ItemsSource = Global.Flows;
break;
case EConfigType.Hysteria2:
@ -113,10 +85,7 @@ public partial class AddServerWindow
cmbFingerprint.IsEnabled = false;
cmbFingerprint.Text = string.Empty;
Global.TuicCongestionControls.ForEach(it =>
{
cmbHeaderType8.Items.Add(it);
});
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
break;
case EConfigType.WireGuard:
@ -128,6 +97,7 @@ public partial class AddServerWindow
break;
}
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
gridTlsMore.Visibility = Visibility.Hidden;
@ -267,44 +237,41 @@ public partial class AddServerWindow
private void SetHeaderType()
{
cmbHeaderType.Items.Clear();
var lstHeaderType = new List<string>();
var network = cmbNetwork.SelectedItem.ToString();
if (network.IsNullOrEmpty())
{
cmbHeaderType.Items.Add(Global.None);
lstHeaderType.Add(Global.None);
cmbHeaderType.ItemsSource = lstHeaderType;
cmbHeaderType.SelectedIndex = 0;
return;
}
if (network == nameof(ETransport.tcp))
{
cmbHeaderType.Items.Add(Global.None);
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
lstHeaderType.Add(Global.None);
lstHeaderType.Add(Global.TcpHeaderHttp);
}
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
{
cmbHeaderType.Items.Add(Global.None);
Global.KcpHeaderTypes.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
lstHeaderType.Add(Global.None);
lstHeaderType.AddRange(Global.KcpHeaderTypes);
}
else if (network is nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
lstHeaderType.AddRange(Global.XhttpMode);
}
else if (network == nameof(ETransport.grpc))
{
cmbHeaderType.Items.Add(Global.GrpcGunMode);
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
lstHeaderType.Add(Global.GrpcGunMode);
lstHeaderType.Add(Global.GrpcMultiMode);
}
else
{
cmbHeaderType.Items.Add(Global.None);
lstHeaderType.Add(Global.None);
}
cmbHeaderType.ItemsSource = lstHeaderType;
cmbHeaderType.SelectedIndex = 0;
}

View file

@ -17,22 +17,10 @@ public partial class DNSSettingWindow
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
Global.DomainStrategy4Freedoms.ForEach(it =>
{
cmbdomainStrategy4Freedom.Items.Add(it);
});
Global.SingboxDomainStrategy4Out.ForEach(it =>
{
cmbdomainStrategy4Out.Items.Add(it);
});
Global.DomainDNSAddress.ForEach(it =>
{
cmbdomainDNSAddress.Items.Add(it);
});
Global.SingboxDomainDNSAddress.ForEach(it =>
{
cmbdomainDNSAddress2.Items.Add(it);
});
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
this.WhenActivated(disposables =>
{

View file

@ -25,11 +25,8 @@ public partial class MsgView
menuMsgViewCopy.Click += menuMsgViewCopy_Click;
menuMsgViewCopyAll.Click += menuMsgViewCopyAll_Click;
menuMsgViewClear.Click += menuMsgViewClear_Click;
Global.PresetMsgFilters.ForEach(it =>
{
cmbMsgFilter.Items.Add(it);
});
cmbMsgFilter.ItemsSource = Global.PresetMsgFilters;
}
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -21,94 +21,39 @@ public partial class OptionSettingWindow
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
Global.destOverrideProtocols.ForEach(it =>
{
clbdestOverride.Items.Add(it);
});
clbdestOverride.ItemsSource = Global.destOverrideProtocols;
_config.Inbound.First().DestOverride?.ForEach(it =>
{
clbdestOverride.SelectedItems.Add(it);
});
Global.IEProxyProtocols.ForEach(it =>
{
cmbsystemProxyAdvancedProtocol.Items.Add(it);
});
Global.LogLevels.ForEach(it =>
{
cmbloglevel.Items.Add(it);
});
Global.Fingerprints.ForEach(it =>
{
cmbdefFingerprint.Items.Add(it);
});
Global.UserAgent.ForEach(it =>
{
cmbdefUserAgent.Items.Add(it);
});
Global.SingboxMuxs.ForEach(it =>
{
cmbmux4SboxProtocol.Items.Add(it);
});
Global.TunMtus.ForEach(it =>
{
cmbMtu.Items.Add(it);
});
Global.TunStacks.ForEach(it =>
{
cmbStack.Items.Add(it);
});
Global.CoreTypes.ForEach(it =>
{
cmbCoreType1.Items.Add(it);
cmbCoreType2.Items.Add(it);
cmbCoreType3.Items.Add(it);
cmbCoreType4.Items.Add(it);
cmbCoreType5.Items.Add(it);
cmbCoreType6.Items.Add(it);
cmbCoreType9.Items.Add(it);
});
cmbsystemProxyAdvancedProtocol.ItemsSource = Global.IEProxyProtocols;
cmbloglevel.ItemsSource = Global.LogLevels;
cmbdefFingerprint.ItemsSource = Global.Fingerprints;
cmbdefUserAgent.ItemsSource = Global.UserAgent;
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
cmbMtu.ItemsSource = Global.TunMtus;
cmbStack.ItemsSource = Global.TunStacks;
for (var i = 2; i <= 8; i++)
{
cmbMixedConcurrencyCount.Items.Add(i);
}
for (var i = 2; i <= 6; i++)
{
cmbSpeedTestTimeout.Items.Add(i * 5);
}
Global.SpeedTestUrls.ForEach(it =>
{
cmbSpeedTestUrl.Items.Add(it);
});
Global.SpeedPingTestUrls.ForEach(it =>
{
cmbSpeedPingTestUrl.Items.Add(it);
});
Global.SubConvertUrls.ForEach(it =>
{
cmbSubConvertUrl.Items.Add(it);
});
Global.GeoFilesSources.ForEach(it =>
{
cmbGetFilesSourceUrl.Items.Add(it);
});
Global.SingboxRulesetSources.ForEach(it =>
{
cmbSrsFilesSourceUrl.Items.Add(it);
});
Global.RoutingRulesSources.ForEach(it =>
{
cmbRoutingRulesSourceUrl.Items.Add(it);
});
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{
cmbMainGirdOrientation.Items.Add(it.ToString());
}
cmbCoreType1.ItemsSource = Global.CoreTypes;
cmbCoreType2.ItemsSource = Global.CoreTypes;
cmbCoreType3.ItemsSource = Global.CoreTypes;
cmbCoreType4.ItemsSource = Global.CoreTypes;
cmbCoreType5.ItemsSource = Global.CoreTypes;
cmbCoreType6.ItemsSource = Global.CoreTypes;
cmbCoreType9.ItemsSource = Global.CoreTypes;
cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(2, 7).ToList();
cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList();
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
cmbGetFilesSourceUrl.ItemsSource = Global.GeoFilesSources;
cmbSrsFilesSourceUrl.ItemsSource = Global.SingboxRulesetSources;
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
this.WhenActivated(disposables =>
{
@ -209,8 +154,7 @@ public partial class OptionSettingWindow
private async Task InitSettingFont()
{
var lstFonts = await GetFonts(Utils.GetFontsPath());
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
cmbcurrentFontFamily.Items.Add(string.Empty);
cmbcurrentFontFamily.ItemsSource = lstFonts.AppendEmpty();
}
private async Task<List<string>> GetFonts(string path)

View file

@ -53,7 +53,8 @@
Grid.Row="0"
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock
Grid.Row="1"
@ -68,6 +69,7 @@
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
IsEditable="True"
MaxDropDownHeight="1000"
Style="{StaticResource DefComboBox}" />
<TextBlock
@ -75,8 +77,9 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
<TextBlock
Grid.Row="2"
@ -97,13 +100,10 @@
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
<TextBlock
Grid.Row="3"
@ -120,6 +120,17 @@
HorizontalAlignment="Left"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="4"
@ -140,6 +151,7 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
@ -164,6 +176,7 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRoutingTips}" />
</Grid>

View file

@ -16,21 +16,11 @@ public partial class RoutingRuleDetailsWindow
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
cmbOutboundTag.Items.Add(Global.ProxyTag);
cmbOutboundTag.Items.Add(Global.DirectTag);
cmbOutboundTag.Items.Add(Global.BlockTag);
Global.RuleProtocols.ForEach(it =>
{
clbProtocol.Items.Add(it);
});
Global.InboundTags.ForEach(it =>
{
clbInboundTag.Items.Add(it);
});
Global.RuleNetworks.ForEach(it =>
{
cmbNetwork.Items.Add(it);
});
cmbOutboundTag.ItemsSource = Global.OutboundTags;
clbProtocol.ItemsSource = Global.RuleProtocols;
clbInboundTag.ItemsSource = Global.InboundTags;
cmbNetwork.ItemsSource = Global.RuleNetworks;
if (!rulesItem.Id.IsNullOrEmpty())
{
@ -74,7 +64,7 @@ public partial class RoutingRuleDetailsWindow
private void Window_Loaded(object sender, RoutedEventArgs e)
{
cmbOutboundTag.Focus();
txtRemarks.Focus();
}
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)

View file

@ -21,15 +21,9 @@ public partial class RoutingRuleSettingWindow
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_Click;
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
Global.DomainStrategies.ForEach(it =>
{
cmbdomainStrategy.Items.Add(it);
});
cmbdomainStrategy.Items.Add(string.Empty);
Global.DomainStrategies4Singbox.ForEach(it =>
{
cmbdomainStrategy4Singbox.Items.Add(it);
});
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
{

View file

@ -21,18 +21,9 @@ public partial class RoutingSettingWindow
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
Global.DomainStrategies.ForEach(it =>
{
cmbdomainStrategy.Items.Add(it);
});
Global.DomainMatchers.ForEach(it =>
{
cmbdomainMatcher.Items.Add(it);
});
Global.DomainStrategies4Singbox.ForEach(it =>
{
cmbdomainStrategy4Singbox.Items.Add(it);
});
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
{

View file

@ -15,10 +15,7 @@ public partial class SubEditWindow
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
Global.SubConvertTargets.ForEach(it =>
{
cmbConvertTarget.Items.Add(it);
});
cmbConvertTarget.ItemsSource = Global.SubConvertTargets;
this.WhenActivated(disposables =>
{

View file

@ -13,22 +13,10 @@ public partial class ThemeSettingView
{
InitializeComponent();
ViewModel = new ThemeSettingViewModel();
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
{
if ((int)it > 2)
continue;
cmbCurrentTheme.Items.Add(it.ToString());
}
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
{
cmbCurrentFontSize.Items.Add(i.ToString());
}
Global.Languages.ForEach(it =>
{
cmbCurrentLanguage.Items.Add(it);
});
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>().Take(3).ToList();
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList();
cmbCurrentLanguage.ItemsSource = Global.Languages;
this.WhenActivated(disposables =>
{