diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 8a2e4c8b..f1613782 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -501,6 +501,31 @@ public class Utils }; } + public static List<(string, string)> ParseHeaders(string? headers) + { + var result = new List<(string, string)>(); + if (headers.IsNullOrEmpty()) + { + return result; + } + var lines = headers.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var parts = line.Split(new[] { ':' }, 2); + if (parts.Length != 2) + { + continue; + } + var key = parts[0].Trim(); + var value = parts[1].Trim(); + if (!string.IsNullOrEmpty(key)) + { + result.Add((key, value)); + } + } + return result; + } + #endregion Conversion Functions #region Data Checks diff --git a/v2rayN/ServiceLib/Enums/EConfigType.cs b/v2rayN/ServiceLib/Enums/EConfigType.cs index 78723c07..e1f8b436 100644 --- a/v2rayN/ServiceLib/Enums/EConfigType.cs +++ b/v2rayN/ServiceLib/Enums/EConfigType.cs @@ -15,6 +15,7 @@ public enum EConfigType Anytls = 11, Naive = 12, Outbound = 13, + MASQUE = 14, PolicyGroup = 101, ProxyChain = 102, } diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 7f645ddc..4f9154ab 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -261,7 +261,8 @@ public class Global { EConfigType.TUIC, "tuic" }, { EConfigType.WireGuard, "wireguard" }, { EConfigType.Anytls, "anytls" }, - { EConfigType.Naive, "naive" } + { EConfigType.Naive, "naive" }, + { EConfigType.MASQUE, "masque" }, }; public static readonly List VmessSecurities = @@ -371,6 +372,7 @@ public class Global EConfigType.Trojan, EConfigType.Hysteria2, EConfigType.WireGuard, + EConfigType.MASQUE, EConfigType.SOCKS, EConfigType.HTTP, ]; @@ -386,6 +388,7 @@ public class Global EConfigType.Anytls, EConfigType.Naive, EConfigType.WireGuard, + EConfigType.MASQUE, EConfigType.SOCKS, EConfigType.HTTP, ]; diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 68c7f490..b09b7391 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -292,6 +292,7 @@ public static class ConfigHandler EConfigType.WireGuard => await AddWireguardServer(config, item), EConfigType.Anytls => await AddAnytlsServer(config, item), EConfigType.Naive => await AddNaiveServer(config, item), + EConfigType.MASQUE => await AddMasqueServer(config, item), _ => -1, }; return ret; @@ -992,6 +993,29 @@ public static class ConfigHandler return 0; } + public static async Task AddMasqueServer(Config config, ProfileItem profileItem, bool toFile = true) + { + profileItem.ConfigType = EConfigType.MASQUE; + + profileItem.Address = profileItem.Address.TrimEx(); + profileItem.Username = profileItem.Username.TrimEx(); + profileItem.Password = profileItem.Password.TrimEx(); + profileItem.Fingerprint = string.Empty; + profileItem.Alpn = string.Empty; + profileItem.Network = string.Empty; + profileItem.AllowInsecure = string.Empty; + if (profileItem.StreamSecurity.IsNullOrEmpty()) + { + profileItem.StreamSecurity = Global.StreamSecurity; + } + if (profileItem.Password.IsNullOrEmpty()) + { + return -1; + } + await AddServerCommon(config, profileItem, toFile); + return 0; + } + /// /// Sort the server list by the specified column /// Updates the sort order in the profile extension data @@ -1684,6 +1708,7 @@ public static class ConfigHandler EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false), EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false), EConfigType.Naive => await AddNaiveServer(config, profileItem, false), + EConfigType.MASQUE => await AddMasqueServer(config, profileItem, false), _ => -1, }; diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs b/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs index 806af4b4..e77b4640 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs @@ -128,8 +128,6 @@ public class User4Sbox public class Outbound4Sbox : BaseServer4Sbox { - public string? server { get; set; } - public int? server_port { get; set; } public List? server_ports { get; set; } public string? uuid { get; set; } public string? security { get; set; } @@ -171,6 +169,10 @@ public class Endpoints4Sbox : BaseServer4Sbox public string? udp_timeout { get; set; } public int? workers { get; set; } public List peers { get; set; } + public string? username { get; set; } + public string? password { get; set; } + public string? path { get; set; } + public Dictionary>? headers { get; set; } } public class Peer4Sbox @@ -271,10 +273,8 @@ public class Server4Sbox : BaseServer4Sbox public string? inet4_range { get; set; } public string? inet6_range { get; set; } public string? client_subnet { get; set; } - public string? server { get; set; } public new string? domain_resolver { get; set; } [JsonPropertyName("interface")] public string? Interface { get; set; } - public int? server_port { get; set; } public string? path { get; set; } public Headers4Sbox? headers { get; set; } @@ -359,4 +359,6 @@ public abstract class BaseServer4Sbox : DialFields4Sbox { public string type { get; set; } public string tag { get; set; } + public string? server { get; set; } + public int? server_port { get; set; } } diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs index cd3561c5..cf3b146b 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs @@ -315,6 +315,7 @@ public class StreamSettings4Ray public GrpcSettings4Ray? grpcSettings { get; set; } public HysteriaSettings4Ray? hysteriaSettings { get; set; } + public MasqueSettings4Ray? masqueSettings { get; set; } public object? finalmask { get; set; } @@ -443,6 +444,12 @@ public class HysteriaSettings4Ray public string? auth { get; set; } } +public class MasqueSettings4Ray +{ + public string? path { get; set; } + public Dictionary? headers { get; set; } +} + public class UdpHop4Ray { public string? ports { get; set; } diff --git a/v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs b/v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs index eb3297b3..eb2059ca 100644 --- a/v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/ProtocolExtraItem.cs @@ -46,6 +46,10 @@ public record ProtocolExtraItem public int? InsecureConcurrency { get; init; } public bool? NaiveQuic { get; init; } + // MASQUE + public string? MasquePath { get; init; } + public string? MasqueHeaders { get; init; } + // group profile public string? GroupType { get; init; } public string? ChildItems { get; init; } diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index b09c309f..a887ad7d 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -789,6 +789,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Add [MASQUE] 的本地化字符串。 + /// + public static string menuAddMasqueServer { + get { + return ResourceManager.GetString("menuAddMasqueServer", resourceCulture); + } + } + /// /// 查找类似 Add [NaïveProxy] 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 294d9709..e8a8c47f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1899,4 +1899,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Process - + + Add [MASQUE] + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 3f5d9cc1..9816d2d4 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1891,4 +1891,7 @@ 进程 - + + 添加 [MASQUE] + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 83f43d2f..5b84c804 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -77,7 +77,7 @@ public partial class CoreConfigSingboxService } } - if (_node.ConfigType == EConfigType.WireGuard) + if (_node.ConfigType is EConfigType.WireGuard or EConfigType.MASQUE) { var endpoint = JsonUtils.Deserialize(txtOutbound); FillEndpoint(endpoint); @@ -350,13 +350,13 @@ public partial class CoreConfigSingboxService { var protocolExtra = _node.GetProtocolExtra(); - endpoint.address = Utils.String2List(protocolExtra.WgInterfaceAddress)?.Select(s => s.Trim()).ToList() ?? ["172.16.0.2/32"]; endpoint.type = Global.ProtocolTypes[_node.ConfigType]; switch (_node.ConfigType) { case EConfigType.WireGuard: { + endpoint.address = Utils.String2List(protocolExtra.WgInterfaceAddress)?.Select(s => s.Trim()).ToList() ?? ["172.16.0.2/32"]; var peer = new Peer4Sbox { public_key = protocolExtra.WgPublicKey ?? string.Empty, @@ -371,6 +371,28 @@ public partial class CoreConfigSingboxService endpoint.peers = [peer]; break; } + case EConfigType.MASQUE: + { + endpoint.type = "masque-client"; + endpoint.server = _node.Address; + endpoint.server_port = _node.Port; + endpoint.username = _node.Username; + endpoint.password = _node.Password; + endpoint.path = protocolExtra?.MasquePath.NullIfEmpty(); + if (!string.IsNullOrEmpty(protocolExtra?.MasqueHeaders)) + { + var headers = Utils.ParseHeaders(protocolExtra.MasqueHeaders) + .GroupBy(x => x.Item1, StringComparer.OrdinalIgnoreCase) + .ToDictionary( + g => g.Key, + g => g.Select(x => x.Item2).ToList(), + StringComparer.OrdinalIgnoreCase + ); + endpoint.headers = headers.Count > 0 ? headers : null; + } + FillOutboundTls(endpoint); + break; + } } } catch (Exception ex) @@ -402,7 +424,7 @@ public partial class CoreConfigSingboxService } } - private void FillOutboundTls(Outbound4Sbox outbound) + private void FillOutboundTls(BaseServer4Sbox server) { try { @@ -476,7 +498,7 @@ public partial class CoreConfigSingboxService { tls.ech = ech; } - outbound.tls = tls; + server.tls = tls; } catch (Exception ex) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index ba726c9f..22ee89e5 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -182,6 +182,12 @@ public partial class CoreConfigV2rayService outboundSettings.version = 2; break; } + case EConfigType.MASQUE: + { + outboundSettings.address = _node.Address; + outboundSettings.port = _node.Port; + break; + } case EConfigType.WireGuard: { var address = _node.Address; @@ -257,8 +263,13 @@ public partial class CoreConfigV2rayService { network = "hysteria"; } + else if (_node.ConfigType == EConfigType.MASQUE) + { + network = "masque"; + } streamSettings.network = network; var transport = _node.GetTransportExtra(); + var protocolExtra = _node.GetProtocolExtra(); var host = string.Empty; var path = string.Empty; var kcpSeed = string.Empty; @@ -502,7 +513,6 @@ public partial class CoreConfigV2rayService break; case "hysteria": - var protocolExtra = _node.GetProtocolExtra(); var ports = protocolExtra?.Ports; int? upMbps = protocolExtra?.UpMbps is { } su and >= 0 ? su @@ -574,6 +584,32 @@ public partial class CoreConfigV2rayService streamSettings.finalmask = hy2Finalmask; break; + case "masque": + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + var authValue = $"Basic {Utils.Base64Encode($"{_node.Username}:{_node.Password}")}"; + headers.Add("Authorization", authValue); + if (!string.IsNullOrEmpty(protocolExtra?.MasqueHeaders)) + { + var userHeaders = Utils.ParseHeaders(protocolExtra.MasqueHeaders) + .GroupBy(x => x.Item1, StringComparer.OrdinalIgnoreCase) + .ToDictionary( + g => g.Key, + g => string.Join(", ", g.Select(x => x.Item2)), + StringComparer.OrdinalIgnoreCase + ); + if (userHeaders.TryGetValue("Authorization", out var userAuthValue)) + { + headers["Authorization"] = userAuthValue; + } + headers = userHeaders; + } + streamSettings.masqueSettings = new() + { + path = protocolExtra?.MasquePath.NullIfEmpty(), + headers = headers.Count > 0 ? headers : null, + }; + break; + default: // raw if (headerType == Global.RawHeaderHttp) diff --git a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs index b8ef98c1..fb89f4fe 100644 --- a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs @@ -97,6 +97,12 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable [Reactive] public partial int GeckoMaxPacketSize { get; set; } + [Reactive] + public partial string MasquePath { get; set; } + + [Reactive] + public partial string MasqueHeaders { get; set; } + [Reactive] public partial string RawHeaderType { get; set; } @@ -322,6 +328,8 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable Hy2RealmUrl = protocolExtra.Hy2RealmUrl ?? string.Empty; GeckoMinPacketSize = protocolExtra.GeckoMinPacketSize.ToInt(); GeckoMaxPacketSize = protocolExtra.GeckoMaxPacketSize.ToInt(); + MasquePath = protocolExtra.MasquePath ?? string.Empty; + MasqueHeaders = protocolExtra.MasqueHeaders ?? string.Empty; RawHeaderType = transport.RawHeaderType ?? Global.None; Host = transport.Host ?? string.Empty; @@ -443,6 +451,8 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable Hy2RealmUrl = realm?.ToUri().NullIfEmpty(), GeckoMinPacketSize = GeckoMinPacketSize > 0 ? GeckoMinPacketSize.ToString() : null, GeckoMaxPacketSize = GeckoMaxPacketSize > 0 ? GeckoMaxPacketSize.ToString() : null, + MasquePath = MasquePath.NullIfEmpty(), + MasqueHeaders = MasqueHeaders.NullIfEmpty(), }); SelectedSource.SetTransportExtra(transport); diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index bb82b327..d13ee64c 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -32,6 +32,7 @@ public partial class MainWindowViewModel : MyReactiveObject public ReactiveCommand AddWireguardServerCmd { get; } public ReactiveCommand AddAnytlsServerCmd { get; } public ReactiveCommand AddNaiveServerCmd { get; } + public ReactiveCommand AddMasqueServerCmd { get; } public ReactiveCommand AddCustomServerCmd { get; } public ReactiveCommand AddCustomOutboundServerCmd { get; } public ReactiveCommand AddPolicyGroupServerCmd { get; } @@ -140,6 +141,10 @@ public partial class MainWindowViewModel : MyReactiveObject { await AddServerAsync(EConfigType.Naive); }); + AddMasqueServerCmd = ReactiveCommand.CreateFromTask(async () => + { + await AddServerAsync(EConfigType.MASQUE); + }); AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () => { await AddServerAsync(EConfigType.Custom); diff --git a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs index 0837571c..4bb29272 100644 --- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs @@ -113,6 +113,7 @@ public partial class OptionSettingViewModel : MyReactiveObject, ICloseable [Reactive] public partial string CoreType6 { get; set; } [Reactive] public partial string CoreType7 { get; set; } [Reactive] public partial string CoreType9 { get; set; } + [Reactive] public partial string CoreType14 { get; set; } #endregion CoreType @@ -283,6 +284,10 @@ public partial class OptionSettingViewModel : MyReactiveObject, ICloseable case 9: CoreType9 = type; break; + + case 14: + CoreType14 = type; + break; } }); await Task.CompletedTask; @@ -451,6 +456,10 @@ public partial class OptionSettingViewModel : MyReactiveObject, ICloseable type = CoreType9; break; + case 14: + type = CoreType14; + break; + default: continue; } diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index fc25b577..d56eb388 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml @@ -783,6 +783,70 @@ HorizontalAlignment="Left" /> + + + + + + + + + + + + + + + this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(currentTypeDisposables); this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(currentTypeDisposables); break; + + case EConfigType.MASQUE: + this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.MasquePath, v => v.txtPath14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.MasqueHeaders, v => v.txtHttpHeaders14.Text).DisposeWith(currentTypeDisposables); + break; + } }) .DisposeWith(disposables); @@ -284,6 +292,14 @@ public partial class AddServerWindow : WindowBase cmbCongestionControl12.ItemsSource = Global.NaiveCongestionControls; break; + + case EConfigType.MASQUE: + gridMasque.IsVisible = true; + sepa2.IsVisible = false; + gridTransport.IsVisible = false; + cmbFingerprint.IsEnabled = false; + cmbAlpn.IsEnabled = false; + break; } cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.SelectedItem = profileItem.StreamSecurity; diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index 21022554..d6d7f776 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -45,6 +45,7 @@ + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index bd2c7902..5ab3a733 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -46,6 +46,7 @@ public partial class MainWindow : WindowBase this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddMasqueServerCmd, v => v.menuAddMasqueServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomOutboundServerCmd, v => v.menuAddCustomOutboundServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml index b509bfa2..e48ff384 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml @@ -1192,7 +1192,7 @@ + RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> + + + diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs index b2f02a21..43c69db6 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs @@ -46,6 +46,7 @@ public partial class OptionSettingWindow : WindowBase cmbCoreType6.ItemsSource = Global.CoreTypes; cmbCoreType7.ItemsSource = Global.CoreTypes; cmbCoreType9.ItemsSource = Global.CoreTypes; + cmbCoreType14.ItemsSource = Global.CoreTypes; cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(Global.SpeedTestConcurrencyCountMin, 20).ToList(); cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList(); @@ -145,6 +146,7 @@ public partial class OptionSettingWindow : WindowBase this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType7, v => v.cmbCoreType7.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType9, v => v.cmbCoreType9.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CoreType14, v => v.cmbCoreType14.SelectedValue).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml index 02071984..7ed92138 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml @@ -1000,6 +1000,89 @@ HorizontalAlignment="Left" /> + + + + + + + + + + + + + + + + + + + + + + + + + + vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(currentTypeDisposables); this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(currentTypeDisposables); break; + + case EConfigType.MASQUE: + this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.MasquePath, v => v.txtPath14.Text).DisposeWith(currentTypeDisposables); + this.Bind(ViewModel, vm => vm.MasqueHeaders, v => v.txtHeaders14.Text).DisposeWith(currentTypeDisposables); + break; } }) .DisposeWith(disposables); @@ -284,6 +291,14 @@ public partial class AddServerWindow cmbCongestionControl12.ItemsSource = Global.NaiveCongestionControls; break; + + case EConfigType.MASQUE: + gridMasque.Visibility = Visibility.Visible; + sepa2.Visibility = Visibility.Collapsed; + gridTransport.Visibility = Visibility.Collapsed; + cmbFingerprint.IsEnabled = false; + cmbAlpn.IsEnabled = false; + break; } cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.SelectedItem = profileItem.StreamSecurity; diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 957a6e31..00d4bf68 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -112,6 +112,10 @@ x:Name="menuAddWireguardServer" Height="{StaticResource MenuItemHeight}" Header="{x:Static resx:ResUI.menuAddWireguardServer}" /> + vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddMasqueServerCmd, v => v.menuAddMasqueServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomOutboundServerCmd, v => v.menuAddCustomOutboundServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml index 6a275dd1..9a60f77a 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml @@ -1473,6 +1473,7 @@ + @@ -1597,6 +1598,21 @@ Width="200" Margin="{StaticResource Margin8}" Style="{StaticResource DefComboBox}" /> + + + diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs index e1dbecd5..1a41bb0a 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs @@ -42,6 +42,7 @@ public partial class OptionSettingWindow cmbCoreType6.ItemsSource = Global.CoreTypes; cmbCoreType7.ItemsSource = Global.CoreTypes; cmbCoreType9.ItemsSource = Global.CoreTypes; + cmbCoreType14.ItemsSource = Global.CoreTypes; cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(Global.SpeedTestConcurrencyCountMin, 20).ToList(); cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList(); @@ -141,6 +142,7 @@ public partial class OptionSettingWindow this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType7, v => v.cmbCoreType7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType9, v => v.cmbCoreType9.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CoreType14, v => v.cmbCoreType14.Text).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); });