Merge branch '2dust:master' into Update

This commit is contained in:
JieXu 2026-04-29 15:11:41 +08:00 committed by GitHub
commit 55ac82cd0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 180 additions and 238 deletions

View file

@ -1,7 +1,7 @@
using System.Reflection;
using ServiceLib.Enums; using ServiceLib.Enums;
using ServiceLib.Manager; using ServiceLib.Manager;
using ServiceLib.Models; using ServiceLib.Models;
using System.Reflection;
namespace ServiceLib.Tests.CoreConfig; namespace ServiceLib.Tests.CoreConfig;
@ -33,7 +33,10 @@ internal static class CoreConfigTestFactory
UiItem = UiItem =
new UIItem new UIItem
{ {
CurrentLanguage = "en", CurrentFontFamily = "sans", MainColumnItem = [], WindowSizeItem = [] CurrentLanguage = "en",
CurrentFontFamily = "sans",
MainColumnItem = [],
WindowSizeItem = []
}, },
ConstItem = new ConstItem(), ConstItem = new ConstItem(),
SpeedTestItem = new SpeedTestItem SpeedTestItem = new SpeedTestItem
@ -51,7 +54,8 @@ internal static class CoreConfigTestFactory
SystemProxyItem = SystemProxyItem =
new SystemProxyItem new SystemProxyItem
{ {
SystemProxyExceptions = string.Empty, SystemProxyAdvancedProtocol = string.Empty SystemProxyExceptions = string.Empty,
SystemProxyAdvancedProtocol = string.Empty
}, },
WebDavItem = new WebDavItem(), WebDavItem = new WebDavItem(),
CheckUpdateItem = new CheckUpdateItem(), CheckUpdateItem = new CheckUpdateItem(),
@ -131,11 +135,15 @@ internal static class CoreConfigTestFactory
{ {
var node = new ProfileItem var node = new ProfileItem
{ {
IndexId = indexId, ConfigType = EConfigType.PolicyGroup, CoreType = coreType, Remarks = remarks, IndexId = indexId,
ConfigType = EConfigType.PolicyGroup,
CoreType = coreType,
Remarks = remarks,
}; };
node.SetProtocolExtra(node.GetProtocolExtra() with node.SetProtocolExtra(node.GetProtocolExtra() with
{ {
GroupType = nameof(EConfigType.PolicyGroup), ChildItems = string.Join(",", childIndexIds), GroupType = nameof(EConfigType.PolicyGroup),
ChildItems = string.Join(",", childIndexIds),
}); });
return node; return node;
@ -146,11 +154,15 @@ internal static class CoreConfigTestFactory
{ {
var node = new ProfileItem var node = new ProfileItem
{ {
IndexId = indexId, ConfigType = EConfigType.ProxyChain, CoreType = coreType, Remarks = remarks, IndexId = indexId,
ConfigType = EConfigType.ProxyChain,
CoreType = coreType,
Remarks = remarks,
}; };
node.SetProtocolExtra(node.GetProtocolExtra() with node.SetProtocolExtra(node.GetProtocolExtra() with
{ {
GroupType = nameof(EConfigType.ProxyChain), ChildItems = string.Join(",", childIndexIds), GroupType = nameof(EConfigType.ProxyChain),
ChildItems = string.Join(",", childIndexIds),
}); });
return node; return node;

View file

@ -1,7 +1,7 @@
using AwesomeAssertions; using AwesomeAssertions;
using ServiceLib.Enums;
using ServiceLib.Handler.Fmt; using ServiceLib.Handler.Fmt;
using ServiceLib.Models; using ServiceLib.Models;
using ServiceLib.Enums;
using Xunit; using Xunit;
namespace ServiceLib.Tests.Fmt; namespace ServiceLib.Tests.Fmt;
@ -92,7 +92,7 @@ public class FmtHandlerTests
var uri = FmtHandler.GetShareUri(source); var uri = FmtHandler.GetShareUri(source);
uri.Should().NotBeNullOrWhiteSpace(); uri.Should().NotBeNullOrWhiteSpace();
(uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase)).Should() uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase).Should()
.BeTrue(); .BeTrue();
var resolved = FmtHandler.ResolveConfig(uri, out var msg); var resolved = FmtHandler.ResolveConfig(uri, out var msg);

View file

@ -239,7 +239,9 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
var clientAddrForSocks = new Socks5AddressData var clientAddrForSocks = new Socks5AddressData
{ {
AddressType = Socks5AddressData.AddrTypeIPv4, Host = "0.0.0.0", Port = 0 AddressType = Socks5AddressData.AddrTypeIPv4,
Host = "0.0.0.0",
Port = 0
}; };
using var udpAssociateReqMs = new MemoryStream(); using var udpAssociateReqMs = new MemoryStream();
udpAssociateReqMs.WriteByte(Socks5Version); udpAssociateReqMs.WriteByte(Socks5Version);
@ -267,7 +269,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
return true; return true;
} }
#endregion #endregion SOCKS5 Connection Handling
#region SOCKS5 Address Handling #region SOCKS5 Address Handling
@ -298,6 +300,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
} }
break; break;
case AddrTypeDomain: case AddrTypeDomain:
if (string.IsNullOrEmpty(Host)) if (string.IsNullOrEmpty(Host))
{ {
@ -311,6 +314,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
} }
break; break;
case AddrTypeIPv6: case AddrTypeIPv6:
if (IPAddress.TryParse(Host, out var ip6) && ip6.AddressFamily == AddressFamily.InterNetworkV6) if (IPAddress.TryParse(Host, out var ip6) && ip6.AddressFamily == AddressFamily.InterNetworkV6)
{ {
@ -322,6 +326,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
} }
break; break;
default: default:
throw new NotSupportedException($"SOCKS5 address type {AddressType} not supported."); throw new NotSupportedException($"SOCKS5 address type {AddressType} not supported.");
} }
@ -355,6 +360,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
addr.Host = new IPAddress(ipv4Bytes).ToString(); addr.Host = new IPAddress(ipv4Bytes).ToString();
break; break;
case AddrTypeDomain: case AddrTypeDomain:
var lenByte = new byte[1]; var lenByte = new byte[1];
if (await stream.ReadAsync(lenByte.AsMemory(0, 1), ct).ConfigureAwait(false) < 1) if (await stream.ReadAsync(lenByte.AsMemory(0, 1), ct).ConfigureAwait(false) < 1)
@ -379,6 +385,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
} }
break; break;
case AddrTypeIPv6: case AddrTypeIPv6:
var ipv6Bytes = new byte[16]; var ipv6Bytes = new byte[16];
if (await stream.ReadAsync(ipv6Bytes.AsMemory(0, 16), ct).ConfigureAwait(false) < 16) if (await stream.ReadAsync(ipv6Bytes.AsMemory(0, 16), ct).ConfigureAwait(false) < 16)
@ -388,6 +395,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
addr.Host = new IPAddress(ipv6Bytes).ToString(); addr.Host = new IPAddress(ipv6Bytes).ToString();
break; break;
default: default:
return null; return null;
} }

View file

@ -4,6 +4,7 @@ public class DnsService : IUdpTest
{ {
private const int DnsDefaultPort = 53; private const int DnsDefaultPort = 53;
private const string DnsDefaultServer = "8.8.8.8"; // Google Public DNS private const string DnsDefaultServer = "8.8.8.8"; // Google Public DNS
private static readonly byte[] DnsQueryPacket = private static readonly byte[] DnsQueryPacket =
[ [
// Header: ID=0x1234, Standard query with RD set, QDCOUNT=1 // Header: ID=0x1234, Standard query with RD set, QDCOUNT=1

View file

@ -3,7 +3,10 @@ namespace ServiceLib.UdpTest.Tester;
public interface IUdpTest public interface IUdpTest
{ {
public byte[] BuildUdpRequestPacket(); public byte[] BuildUdpRequestPacket();
public bool VerifyAndExtractUdpResponse(byte[] udpResponseBytes); public bool VerifyAndExtractUdpResponse(byte[] udpResponseBytes);
public ushort GetDefaultTargetPort(); public ushort GetDefaultTargetPort();
public string GetDefaultTargetHost(); public string GetDefaultTargetHost();
} }

View file

@ -4,6 +4,7 @@ public class McBeService : IUdpTest
{ {
private const int McBeDefaultPort = 19132; private const int McBeDefaultPort = 19132;
private const string McBeDefaultServer = "pms.mc-complex.com"; private const string McBeDefaultServer = "pms.mc-complex.com";
// 0x01 | client alive time in ms (unsigned long long) | magic | client GUID // 0x01 | client alive time in ms (unsigned long long) | magic | client GUID
private static readonly byte[] McBeQueryPacket = private static readonly byte[] McBeQueryPacket =
[ [
@ -18,11 +19,13 @@ public class McBeService : IUdpTest
0x66, 0x0E, 0xAB, 0xBC, 0x61, 0x0D, 0x1F, 0x4E, 0x66, 0x0E, 0xAB, 0xBC, 0x61, 0x0D, 0x1F, 0x4E,
0xA4, 0x40, 0x8C, 0x65, 0xC1, 0xBE, 0xF5, 0x4B 0xA4, 0x40, 0x8C, 0x65, 0xC1, 0xBE, 0xF5, 0x4B
]; ];
private static readonly byte[] McBeMagicBytes = private static readonly byte[] McBeMagicBytes =
[ [
0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78
]; ];
private static readonly List<string> ValidGameModes = private static readonly List<string> ValidGameModes =
[ [
"Survival", "Survival",

View file

@ -4,6 +4,7 @@ public class StunService : IUdpTest
{ {
private const int StunDefaultPort = 3478; private const int StunDefaultPort = 3478;
private const string StunDefaultServer = "stun.voztovoice.org"; private const string StunDefaultServer = "stun.voztovoice.org";
private static readonly byte[] StunBindingRequestPacket = private static readonly byte[] StunBindingRequestPacket =
[ [
// STUN Binding Request // STUN Binding Request

View file

@ -691,14 +691,6 @@ public class Global
"" ""
]; ];
public static readonly List<string> EchForceQuerys =
[
"none",
"half",
"full",
""
];
public static readonly List<string> TunIcmpRoutingPolicies = public static readonly List<string> TunIcmpRoutingPolicies =
[ [
"rule", "rule",

View file

@ -256,7 +256,6 @@ public static class ConfigHandler
item.Cert = profileItem.Cert; item.Cert = profileItem.Cert;
item.CertSha = profileItem.CertSha; item.CertSha = profileItem.CertSha;
item.EchConfigList = profileItem.EchConfigList; item.EchConfigList = profileItem.EchConfigList;
item.EchForceQuery = profileItem.EchForceQuery;
item.Finalmask = profileItem.Finalmask; item.Finalmask = profileItem.Finalmask;
item.ProtoExtra = profileItem.ProtoExtra; item.ProtoExtra = profileItem.ProtoExtra;
item.TransportExtra = profileItem.TransportExtra; item.TransportExtra = profileItem.TransportExtra;

View file

@ -5,6 +5,7 @@ namespace ServiceLib.Handler.Fmt;
public class BaseFmt public class BaseFmt
{ {
private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" }; private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" };
private static string UrlEncodeSafe(string? value) => Utils.UrlEncode(value ?? string.Empty); private static string UrlEncodeSafe(string? value) => Utils.UrlEncode(value ?? string.Empty);
protected static string GetIpv6(string address) protected static string GetIpv6(string address)

View file

@ -191,7 +191,6 @@ public class ProfileItem
public string Cert { get; set; } public string Cert { get; set; }
public string CertSha { get; set; } public string CertSha { get; set; }
public string EchConfigList { get; set; } public string EchConfigList { get; set; }
public string EchForceQuery { get; set; }
public string Finalmask { get; set; } public string Finalmask { get; set; }
public string ProtoExtra { get; set; } public string ProtoExtra { get; set; }

View file

@ -237,6 +237,7 @@ public class Transport4Sbox
public class Headers4Sbox public class Headers4Sbox
{ {
public string? Host { get; set; } public string? Host { get; set; }
[JsonPropertyName("User-Agent")] [JsonPropertyName("User-Agent")]
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }

View file

@ -500,12 +500,16 @@ public class MaskSettings4Ray
{ {
public string? password { get; set; } public string? password { get; set; }
public string? domain { get; set; } public string? domain { get; set; }
// fragment // fragment
public string? packets { get; set; } public string? packets { get; set; }
public string? length { get; set; } public string? length { get; set; }
public string? delay { get; set; } public string? delay { get; set; }
// noise // noise
public int? reset { get; set; } public int? reset { get; set; }
public List<NoiseMask4Ray>? noise { get; set; } public List<NoiseMask4Ray>? noise { get; set; }
} }
@ -533,6 +537,7 @@ public class AccountsItem4Ray
public class Sockopt4Ray public class Sockopt4Ray
{ {
public string? dialerProxy { get; set; } public string? dialerProxy { get; set; }
[JsonPropertyName("interface")] [JsonPropertyName("interface")]
public string? Interface { get; set; } public string? Interface { get; set; }
} }

View file

@ -2881,7 +2881,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。 /// 查找类似 Please fill in DNS Object; Click to view documentation 的本地化字符串。
/// </summary> /// </summary>
public static string TbDnsObjectDoc { public static string TbDnsObjectDoc {
get { get {
@ -2943,15 +2943,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 EchForceQuery 的本地化字符串。
/// </summary>
public static string TbEchForceQuery {
get {
return ResourceManager.GetString("TbEchForceQuery", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Edit 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>
@ -4158,15 +4149,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Custom DNS (multiple, separated by commas (,)) 的本地化字符串。
/// </summary>
public static string TbSettingsRemoteDNS {
get {
return ResourceManager.GetString("TbSettingsRemoteDNS", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Route Only 的本地化字符串。 /// 查找类似 Route Only 的本地化字符串。
/// </summary> /// </summary>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>مجوز احراز هویت</value> <value>مجوز احراز هویت</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>سفارشی DNS (multiple, separated by commas (,))</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>تنظیم کردن Win10 UWP Loopback</value> <value>تنظیم کردن Win10 UWP Loopback</value>
</data> </data>
@ -1584,9 +1581,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Full certificate (chain), PEM format</value> <value>Full certificate (chain), PEM format</value>
</data> </data>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Mot de passe dauthentification</value> <value>Mot de passe dauthentification</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>DNS perso (plusieurs configurables, séparés par virgules)</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Lever la restriction de proxy en boucle locale pour les applications Win10 UWP</value> <value>Lever la restriction de proxy en boucle locale pour les applications Win10 UWP</value>
</data> </data>
@ -1590,9 +1587,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Certificat complet (chaîne), format PEM</value> <value>Certificat complet (chaîne), format PEM</value>
</data> </data>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Hitelesítési jelszó</value> <value>Hitelesítési jelszó</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Egyéni DNS (több, vesszővel (,) elválasztva)</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Win10 UWP Loopback beállítása</value> <value>Win10 UWP Loopback beállítása</value>
</data> </data>
@ -1584,9 +1581,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Full certificate (chain), PEM format</value> <value>Full certificate (chain), PEM format</value>
</data> </data>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value> <value>Auth pass</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Custom DNS (multiple, separated by commas (,))</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Set Win10 UWP Loopback</value> <value>Set Win10 UWP Loopback</value>
</data> </data>
@ -862,7 +859,7 @@
<value>Rule object Doc</value> <value>Rule object Doc</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>Supports DNS Object; Click to view documentation</value> <value>Please fill in DNS Object; Click to view documentation</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>For group please leave blank here</value> <value>For group please leave blank here</value>
@ -1593,9 +1590,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Full certificate (chain), PEM format</value> <value>Full certificate (chain), PEM format</value>
</data> </data>

View file

@ -673,7 +673,7 @@
<value>Ядро: базовые настройки</value> <value>Ядро: базовые настройки</value>
</data> </data>
<data name="TbCustomDnsRay" xml:space="preserve"> <data name="TbCustomDnsRay" xml:space="preserve">
<value>Пользовательский DNS для V2ray</value> <value>Пользовательский DNS для v2ray</value>
</data> </data>
<data name="TbSettingsCoreKcp" xml:space="preserve"> <data name="TbSettingsCoreKcp" xml:space="preserve">
<value>Ядро: настройки KCP</value> <value>Ядро: настройки KCP</value>
@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Пароль авторизации</value> <value>Пароль авторизации</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Пользовательский DNS (если несколько, то делите запятыми (,))</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Разрешить loopback для приложений UWP (Win10)</value> <value>Разрешить loopback для приложений UWP (Win10)</value>
</data> </data>
@ -934,7 +931,7 @@
<value>User-Agent</value> <value>User-Agent</value>
</data> </data>
<data name="TbSettingsDefUserAgentTips" xml:space="preserve"> <data name="TbSettingsDefUserAgentTips" xml:space="preserve">
<value>This parameter is valid only for raw/http, ws, gRPC and xhttp</value> <value>Параметр действует только для raw/http, ws, gRPC и xhttp</value>
</data> </data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve"> <data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>Шрифт (требуется перезапуск)</value> <value>Шрифт (требуется перезапуск)</value>
@ -1321,7 +1318,7 @@
<value>XHTTP-режим</value> <value>XHTTP-режим</value>
</data> </data>
<data name="TransportExtraTip" xml:space="preserve"> <data name="TransportExtraTip" xml:space="preserve">
<value>Raw JSON, format: { XHTTP Object }</value> <value>Сырой JSON, формат: { XHTTP Object }</value>
</data> </data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Сворачивать в трей при закрытии окна</value> <value>Сворачивать в трей при закрытии окна</value>
@ -1339,7 +1336,7 @@
<value>Включить второй смешанный порт</value> <value>Включить второй смешанный порт</value>
</data> </data>
<data name="TbRoutingInboundTagTips" xml:space="preserve"> <data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks: локальный порт, socks2: второй локальный порт, socks3: LAN порт</value> <value>socks: локальный порт, socks2: второй локальный порт, socks3: LAN-порт</value>
</data> </data>
<data name="TbSettingsTheme" xml:space="preserve"> <data name="TbSettingsTheme" xml:space="preserve">
<value>Тема</value> <value>Тема</value>
@ -1381,7 +1378,7 @@
<value>Mldsa65Verify</value> <value>Mldsa65Verify</value>
</data> </data>
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Добавить сервер [Anytls]</value> <value>Добавить сервер [AnyTLS]</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve"> <data name="TbRemoteDNS" xml:space="preserve">
<value>Удалённый DNS</value> <value>Удалённый DNS</value>
@ -1584,9 +1581,6 @@
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Полный сертификат (цепочка) в формате PEM</value> <value>Полный сертификат (цепочка) в формате PEM</value>
</data> </data>
@ -1696,27 +1690,33 @@
<value>Устаревшая защита TUN (Legacy Protect)</value> <value>Устаревшая защита TUN (Legacy Protect)</value>
</data> </data>
<data name="TbSettingsSendThroughTip" xml:space="preserve"> <data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value> <value>Для среды с несколькими сетевыми интерфейсами укажите IPv4-адрес локального компьютера</value>
</data> </data>
<data name="TbCamouflageDomain" xml:space="preserve"> <data name="TbCamouflageDomain" xml:space="preserve">
<value>Камуфляжный домен</value> <value>Камуфляжный домен</value>
</data> </data>
<data name="TbHost" xml:space="preserve"> <data name="TbHost" xml:space="preserve">
<value>Host</value> <value>Хост</value>
</data> </data>
<data name="TransportExtra" xml:space="preserve"> <data name="TransportExtra" xml:space="preserve">
<value>XHTTP Extra</value> <value>Дополнительные параметры XHTTP (Extra)</value>
</data> </data>
<data name="TbAllowInsecureCertFetch" xml:space="preserve"> <data name="TbAllowInsecureCertFetch" xml:space="preserve">
<value>Allow insecure cert fetch (self-signed)</value> <value>Разрешить небезопасную загрузку сертификата (самоподписанного)</value>
</data> </data>
<data name="TbAllowInsecureCertFetchTips" xml:space="preserve"> <data name="TbAllowInsecureCertFetchTips" xml:space="preserve">
<value>Only for fetching self-signed certificates. This may expose you to MITM risks.</value> <value>Только для загрузки самоподписанных сертификатов. Это может подвергнуть вас риску атаки «человек посередине» (MITM).</value>
</data> </data>
<data name="menuUdpTestServer" xml:space="preserve"> <data name="menuUdpTestServer" xml:space="preserve">
<value>Test Configurations UDP Delay</value> <value>Тест UDP-задержки конфигураций</value>
</data> </data>
<data name="TbSettingsUdpTestUrl" xml:space="preserve"> <data name="TbSettingsUdpTestUrl" xml:space="preserve">
<value>UDP Test Url</value> <value>URL для UDP-теста</value>
</data>
<data name="FillCorrectSendThroughIPv4" xml:space="preserve">
<value>Укажите корректный IPv4-адрес для SendThrough.</value>
</data>
<data name="TbSettingsSendThrough" xml:space="preserve">
<value>Локальный исходящий адрес (SendThrough)</value>
</data> </data>
</root> </root>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>认证密码</value> <value>认证密码</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>自定义 DNS (可多个,用逗号 (,) 分隔)</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>解除 Win10 UWP 应用回环代理限制</value> <value>解除 Win10 UWP 应用回环代理限制</value>
</data> </data>
@ -862,7 +859,7 @@
<value>规则详细说明文档</value> <value>规则详细说明文档</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>支持填写 DnsObjectJSON 格式,点击查看文档</value> <value>填写 DnsObjectJSON 格式,点击查看文档</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>普通分组此处请留空</value> <value>普通分组此处请留空</value>
@ -1590,9 +1587,6 @@
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>完整证书PEM 格式</value> <value>完整证书PEM 格式</value>
</data> </data>

View file

@ -720,9 +720,6 @@
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>認證密碼</value> <value>認證密碼</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>自訂 DNS (可多個,用逗號 (,) 分隔)</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>解除 Win10 UWP 應用回環代理限制</value> <value>解除 Win10 UWP 應用回環代理限制</value>
</data> </data>
@ -862,7 +859,7 @@
<value>規則詳細說明檔案</value> <value>規則詳細說明檔案</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>支援填寫 DnsObjectJSON 格式,點擊查看說明</value> <value>填寫 DnsObjectJSON 格式,點擊查看說明</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>普通分組此處請留空</value> <value>普通分組此處請留空</value>
@ -1581,9 +1578,6 @@
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
</data> </data>
<data name="TbEchForceQuery" xml:space="preserve">
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>完整憑證PEM 格式</value> <value>完整憑證PEM 格式</value>
</data> </data>

View file

@ -383,7 +383,6 @@ public partial class CoreConfigV2rayService
alpn = _node.GetAlpn(), alpn = _node.GetAlpn(),
fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint, fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint,
echConfigList = _node.EchConfigList.NullIfEmpty(), echConfigList = _node.EchConfigList.NullIfEmpty(),
echForceQuery = _node.EchForceQuery.NullIfEmpty()
}; };
if (sni.IsNotEmpty()) if (sni.IsNotEmpty())
{ {
@ -393,6 +392,11 @@ public partial class CoreConfigV2rayService
{ {
tlsSettings.serverName = Utils.String2List(host)?.First(); tlsSettings.serverName = Utils.String2List(host)?.First();
} }
if (!tlsSettings.echConfigList.IsNullOrEmpty())
{
// For legacy xray compatibility, remove this in the future
tlsSettings.echForceQuery = "full";
}
var certs = CertPemManager.ParsePemChain(_node.Cert); var certs = CertPemManager.ParsePemChain(_node.Cert);
if (certs.Count > 0) if (certs.Count > 0)
{ {
@ -548,6 +552,7 @@ public partial class CoreConfigV2rayService
FillOutboundMux(outbound); FillOutboundMux(outbound);
break; break;
case nameof(ETransport.grpc): case nameof(ETransport.grpc):
GrpcSettings4Ray grpcSettings = new() GrpcSettings4Ray grpcSettings = new()
{ {

View file

@ -299,7 +299,6 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
return url; return url;
} }
else if (Utils.IsLinux()) else if (Utils.IsLinux())
{ {
return RuntimeInformation.ProcessArchitecture switch return RuntimeInformation.ProcessArchitecture switch
@ -310,7 +309,6 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
_ => null, _ => null,
}; };
} }
else if (Utils.IsMacOS()) else if (Utils.IsMacOS())
{ {
return RuntimeInformation.ProcessArchitecture switch return RuntimeInformation.ProcessArchitecture switch

View file

@ -306,7 +306,7 @@
x:Name="txtSecurity5" x:Name="txtSecurity5"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
@ -1115,19 +1115,6 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbEchForceQuery}" />
<ComboBox
x:Name="cmbEchForceQuery"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -39,11 +39,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns; cmbAlpn.ItemsSource = Global.Alpns;
cmbEchForceQuery.ItemsSource = Global.EchForceQuerys;
var lstStreamSecurity = new List<string>(); var lstStreamSecurity = new List<string> { string.Empty, Global.StreamSecurity };
lstStreamSecurity.Add(string.Empty);
lstStreamSecurity.Add(Global.StreamSecurity);
switch (profileItem.ConfigType) switch (profileItem.ConfigType)
{ {
@ -246,7 +243,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.togAllowInsecureCertFetch.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.togAllowInsecureCertFetch.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.txtAllowInsecureCertFetchTips.IsVisible).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.txtAllowInsecureCertFetchTips.IsVisible).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.SelectedValue).DisposeWith(disposables);
//reality //reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
@ -338,21 +334,27 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case nameof(ETransport.raw): case nameof(ETransport.raw):
gridTransportRaw.IsVisible = true; gridTransportRaw.IsVisible = true;
break; break;
case nameof(ETransport.kcp): case nameof(ETransport.kcp):
gridTransportKcp.IsVisible = true; gridTransportKcp.IsVisible = true;
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
gridTransportWs.IsVisible = true; gridTransportWs.IsVisible = true;
break; break;
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
gridTransportHttpupgrade.IsVisible = true; gridTransportHttpupgrade.IsVisible = true;
break; break;
case nameof(ETransport.xhttp): case nameof(ETransport.xhttp):
gridTransportXhttp.IsVisible = true; gridTransportXhttp.IsVisible = true;
break; break;
case nameof(ETransport.grpc): case nameof(ETransport.grpc):
gridTransportGrpc.IsVisible = true; gridTransportGrpc.IsVisible = true;
break; break;
default: default:
gridTransportRaw.IsVisible = true; gridTransportRaw.IsVisible = true;
break; break;

View file

@ -342,11 +342,6 @@
</StackPanel> </StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal"> <StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center"> <TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click"> <HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" /> <TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
@ -494,7 +489,6 @@
Header="{x:Static resx:ResUI.TbSettingsTunMode}"> Header="{x:Static resx:ResUI.TbSettingsTunMode}">
<local:JsonEditor Name="txttunDNS2Compatible" VerticalAlignment="Stretch" /> <local:JsonEditor Name="txttunDNS2Compatible" VerticalAlignment="Stretch" />
</HeaderedContentControl> </HeaderedContentControl>
</Grid> </Grid>
</DockPanel> </DockPanel>
</TabItem> </TabItem>

View file

@ -64,7 +64,10 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e) private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
{ {
if (_closed) return; if (_closed)
{
return;
}
// DomainStrategy is auto-saved reactively; just ensure the caller knows changes were made // DomainStrategy is auto-saved reactively; just ensure the caller knows changes were made
if (ViewModel?.IsModified == true) if (ViewModel?.IsModified == true)

View file

@ -137,7 +137,7 @@ public class ThemeSettingViewModel : MyReactiveObject
private void ModifyFontSize() private void ModifyFontSize()
{ {
double size = (long)CurrentFontSize; double size = CurrentFontSize;
if (size < Global.MinFontSize) if (size < Global.MinFontSize)
{ {
return; return;

View file

@ -415,7 +415,7 @@
x:Name="txtSecurity5" x:Name="txtSecurity5"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
@ -1444,21 +1444,6 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbEchForceQuery}" />
<ComboBox
x:Name="cmbEchForceQuery"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -38,11 +38,8 @@ public partial class AddServerWindow
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns; cmbAlpn.ItemsSource = Global.Alpns;
cmbEchForceQuery.ItemsSource = Global.EchForceQuerys;
var lstStreamSecurity = new List<string>(); var lstStreamSecurity = new List<string> { string.Empty, Global.StreamSecurity };
lstStreamSecurity.Add(string.Empty);
lstStreamSecurity.Add(Global.StreamSecurity);
switch (profileItem.ConfigType) switch (profileItem.ConfigType)
{ {
@ -247,7 +244,6 @@ public partial class AddServerWindow
.BindTo(this, v => v.txtAllowInsecureCertFetchTips.Visibility); .BindTo(this, v => v.txtAllowInsecureCertFetchTips.Visibility);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.Text).DisposeWith(disposables);
//reality //reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
@ -340,21 +336,27 @@ public partial class AddServerWindow
case nameof(ETransport.raw): case nameof(ETransport.raw):
gridTransportRaw.Visibility = Visibility.Visible; gridTransportRaw.Visibility = Visibility.Visible;
break; break;
case nameof(ETransport.kcp): case nameof(ETransport.kcp):
gridTransportKcp.Visibility = Visibility.Visible; gridTransportKcp.Visibility = Visibility.Visible;
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
gridTransportWs.Visibility = Visibility.Visible; gridTransportWs.Visibility = Visibility.Visible;
break; break;
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
gridTransportHttpupgrade.Visibility = Visibility.Visible; gridTransportHttpupgrade.Visibility = Visibility.Visible;
break; break;
case nameof(ETransport.xhttp): case nameof(ETransport.xhttp):
gridTransportXhttp.Visibility = Visibility.Visible; gridTransportXhttp.Visibility = Visibility.Visible;
break; break;
case nameof(ETransport.grpc): case nameof(ETransport.grpc):
gridTransportGrpc.Visibility = Visibility.Visible; gridTransportGrpc.Visibility = Visibility.Visible;
break; break;
default: default:
gridTransportRaw.Visibility = Visibility.Visible; gridTransportRaw.Visibility = Visibility.Visible;
break; break;

View file

@ -390,11 +390,6 @@
</StackPanel> </StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal"> <StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<TextBlock <TextBlock
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"

View file

@ -170,10 +170,10 @@ public partial class MainWindow
private void OnProgramStarted(object state, bool timeout) private void OnProgramStarted(object state, bool timeout)
{ {
Application.Current?.Dispatcher.Invoke((Action)(() => Application.Current?.Dispatcher.Invoke(() =>
{ {
ShowHideWindow(true); ShowHideWindow(true);
})); });
} }
private async Task DelegateSnackMsg(string content) private async Task DelegateSnackMsg(string content)