mirror of
https://github.com/2dust/v2rayN.git
synced 2026-07-27 10:22:06 +03:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1de83f96ed | ||
|
|
994bc1ca6a | ||
|
|
3ca49dd9db | ||
|
|
a0bd8f9934 | ||
|
|
88d59488fd | ||
|
|
2c70b018ce | ||
|
|
b6ab428dfc | ||
|
|
45ab7503e3 | ||
|
|
1768b4a7ee |
9
.github/workflows/winget-publish.yml
vendored
9
.github/workflows/winget-publish.yml
vendored
@@ -23,8 +23,13 @@ jobs:
|
||||
|
||||
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
||||
|
||||
$x64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip' | Select -ExpandProperty browser_download_url
|
||||
$arm64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-arm64\.zip' | Select -ExpandProperty browser_download_url
|
||||
$assets = $targetRelease | Select -ExpandProperty assets -First 1
|
||||
$x64InstallerUrl = $assets | Where-Object { $_.name -eq 'v2rayN-windows-64.zip' } | Select -ExpandProperty browser_download_url
|
||||
$arm64InstallerUrl = $assets | Where-Object { $_.name -eq 'v2rayN-windows-arm64.zip' } | Select -ExpandProperty browser_download_url
|
||||
|
||||
if (-not $x64InstallerUrl -or -not $arm64InstallerUrl) {
|
||||
throw "Could not find required installers in release assets."
|
||||
}
|
||||
|
||||
$ver = $targetRelease.tag_name
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.23.3</Version>
|
||||
<Version>7.23.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -130,6 +130,25 @@ internal static class CoreConfigTestFactory
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileItem CreateHttpNode(ECoreType coreType, string indexId = "node-http-1",
|
||||
string remarks = "demo-http")
|
||||
{
|
||||
return new ProfileItem
|
||||
{
|
||||
IndexId = indexId,
|
||||
ConfigType = EConfigType.HTTP,
|
||||
CoreType = coreType,
|
||||
Remarks = remarks,
|
||||
Address = "proxy.example.com",
|
||||
Port = 8080,
|
||||
Password = "pass",
|
||||
Username = "user",
|
||||
Network = nameof(ETransport.raw),
|
||||
StreamSecurity = string.Empty,
|
||||
Subid = string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileItem CreatePolicyGroupNode(ECoreType coreType, string indexId, string remarks,
|
||||
IEnumerable<string> childIndexIds)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,39 @@ public class CoreConfigV2rayServiceTests
|
||||
v2rayConfig.inbounds.Should().Contain(i => i.protocol == nameof(EInboundProtocol.mixed));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateClientConfigContent_HttpOutbound_ShouldEmitHeadersInSettings()
|
||||
{
|
||||
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||
var node = CoreConfigTestFactory.CreateHttpNode(ECoreType.Xray);
|
||||
node.SetProtocolExtra(node.GetProtocolExtra() with
|
||||
{
|
||||
HttpHeaders = "{\"User-Agent\":\"v2rayN\",\"Set-Cookie\":[\"a=1\",\"b=2\"]}",
|
||||
});
|
||||
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.Xray);
|
||||
|
||||
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
var cfg = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!;
|
||||
var outbound = cfg.outbounds.First(o => o.tag == Global.ProxyTag && o.protocol == "http");
|
||||
|
||||
outbound.settings.address?.ToString().Should().Be("proxy.example.com");
|
||||
outbound.settings.port.Should().Be(8080);
|
||||
outbound.settings.user.Should().Be("user");
|
||||
outbound.settings.pass.Should().Be("pass");
|
||||
outbound.settings.level.Should().Be(1);
|
||||
outbound.settings.headers.Should().NotBeNull();
|
||||
var headers = JsonUtils.ParseJson(outbound.settings.headers.ToString());
|
||||
headers["User-Agent"]!.GetValue<string>().Should().Be("v2rayN");
|
||||
headers["Set-Cookie"]!.AsArray()
|
||||
.Select(item => item!.GetValue<string>())
|
||||
.Should().Equal("a=1", "b=2");
|
||||
outbound.settings.servers.Should().BeNull();
|
||||
outbound.settings.vnext.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildBalancer()
|
||||
{
|
||||
|
||||
@@ -164,7 +164,7 @@ public static class ConfigHandler
|
||||
config.ClashUIItem.ConnectionsColumnItem ??= [];
|
||||
config.SystemProxyItem ??= new();
|
||||
config.WebDavItem ??= new();
|
||||
config.CheckUpdateItem ??= new();
|
||||
config.CheckUpdateItem ??= new();
|
||||
config.Fragment4RayItem ??= new()
|
||||
{
|
||||
Packets = "tlshello",
|
||||
|
||||
@@ -288,6 +288,7 @@ public class CertPemManager
|
||||
collection.ImportFromPem(pemText);
|
||||
return collection;
|
||||
});
|
||||
|
||||
private static readonly Lazy<X509Certificate2Collection> _mozillaRootCerts = new(() =>
|
||||
{
|
||||
var pemText = EmbedUtils.GetEmbedText(Global.MozillaRootCertFileName);
|
||||
@@ -295,6 +296,7 @@ public class CertPemManager
|
||||
collection.ImportFromPem(pemText);
|
||||
return collection;
|
||||
});
|
||||
|
||||
private X509Certificate2Collection BuildTrustedCertificateCollection()
|
||||
{
|
||||
if (_config.GuiItem.RootCertProvider == Global.ChromeRootProvider)
|
||||
|
||||
@@ -8,8 +8,10 @@ public class CoreManager
|
||||
private static readonly Lazy<CoreManager> _instance = new(() => new());
|
||||
public static CoreManager Instance => _instance.Value;
|
||||
private Config _config;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
private WindowsJobService? _processJob;
|
||||
|
||||
private ProcessService? _processService;
|
||||
private ProcessService? _processPreService;
|
||||
private bool _linuxSudo = false;
|
||||
|
||||
@@ -103,6 +103,7 @@ public class UIItem
|
||||
public bool MacOSShowInDock { get; set; }
|
||||
public List<ColumnItem> MainColumnItem { get; set; }
|
||||
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
||||
public bool HideColumnIpInfo { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -146,6 +146,16 @@ public class Outboundsettings4Ray
|
||||
|
||||
public int? port { get; set; }
|
||||
|
||||
public string? user { get; set; }
|
||||
|
||||
public string? pass { get; set; }
|
||||
|
||||
public int? level { get; set; }
|
||||
|
||||
public string? email { get; set; }
|
||||
|
||||
public object? headers { get; set; }
|
||||
|
||||
public List<WireguardPeer4Ray>? peers { get; set; }
|
||||
|
||||
public bool? noKernelTun { get; set; }
|
||||
@@ -276,7 +286,6 @@ public class BalancersItem4Ray
|
||||
public List<string>? selector { get; set; }
|
||||
public BalancersStrategy4Ray? strategy { get; set; }
|
||||
public string? tag { get; set; }
|
||||
public string? fallbackTag { get; set; }
|
||||
}
|
||||
|
||||
public class BalancersStrategy4Ray
|
||||
|
||||
@@ -5,6 +5,9 @@ public record ProtocolExtraItem
|
||||
public bool? Uot { get; init; }
|
||||
public string? CongestionControl { get; init; }
|
||||
|
||||
// http outbound
|
||||
public string? HttpHeaders { get; init; }
|
||||
|
||||
// vmess
|
||||
public string? AlterId { get; init; }
|
||||
public string? VmessSecurity { get; init; }
|
||||
|
||||
27
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
27
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -321,6 +321,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Please enter valid HTTP request headers JSON. 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string InvalidHttpOutboundHeaders {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidHttpOutboundHeaders", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Invalid Realm URL. 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3240,6 +3249,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 HTTP headers 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbHttpOutboundHeaders {
|
||||
get {
|
||||
return ResourceManager.GetString("TbHttpOutboundHeaders", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Realm URL 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4986,6 +5004,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Custom HTTP outbound request headers as a JSON object with string or string array values. 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TipHttpOutboundHeaders {
|
||||
get {
|
||||
return ResourceManager.GetString("TipHttpOutboundHeaders", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 *Default value raw 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1044,6 +1044,12 @@
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>Congestion control</value>
|
||||
</data>
|
||||
<data name="TbHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>HTTP headers</value>
|
||||
</data>
|
||||
<data name="TipHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>Custom HTTP outbound request headers as a JSON object with string or string array values.</value>
|
||||
</data>
|
||||
<data name="LvPrevProfile" xml:space="preserve">
|
||||
<value>Previous proxy remarks</value>
|
||||
</data>
|
||||
@@ -1806,6 +1812,9 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="InvalidHy2RealmUrl" xml:space="preserve">
|
||||
<value>Invalid Realm URL.</value>
|
||||
</data>
|
||||
<data name="InvalidHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>Please enter valid HTTP request headers JSON.</value>
|
||||
</data>
|
||||
<data name="TbHy2RealmUrlTip" xml:space="preserve">
|
||||
<value>Format: realm://<token>@<rendezvous-host>[:port]/<realm-name>?stun=<stun-host>[:port]</value>
|
||||
</data>
|
||||
@@ -1821,4 +1830,4 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -1041,6 +1041,12 @@
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>拥塞控制算法</value>
|
||||
</data>
|
||||
<data name="TbHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>HTTP 请求头</value>
|
||||
</data>
|
||||
<data name="TipHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>自定义 HTTP 出站请求头,请输入值为字符串或字符串数组的 JSON 对象。</value>
|
||||
</data>
|
||||
<data name="LvPrevProfile" xml:space="preserve">
|
||||
<value>前置代理配置别名</value>
|
||||
</data>
|
||||
@@ -1803,6 +1809,9 @@
|
||||
<data name="InvalidHy2RealmUrl" xml:space="preserve">
|
||||
<value>Realm URL 不正确。</value>
|
||||
</data>
|
||||
<data name="InvalidHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>请填写合法的HTTP请求头JSON。</value>
|
||||
</data>
|
||||
<data name="TbHy2RealmUrlTip" xml:space="preserve">
|
||||
<value>格式:realm://<token>@<rendezvous-host>[:port]/<realm-name>?stun=<stun-host>[:port]</value>
|
||||
</data>
|
||||
@@ -1818,4 +1827,4 @@
|
||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -1041,6 +1041,12 @@
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>擁塞控制算法</value>
|
||||
</data>
|
||||
<data name="TbHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>HTTP 請求頭</value>
|
||||
</data>
|
||||
<data name="TipHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>自訂 HTTP 出站請求頭,請輸入值為字串或字串陣列的 JSON 物件。</value>
|
||||
</data>
|
||||
<data name="LvPrevProfile" xml:space="preserve">
|
||||
<value>前置代理節點別名</value>
|
||||
</data>
|
||||
@@ -1797,4 +1803,7 @@
|
||||
<data name="TbLegacyProtectTip" xml:space="preserve">
|
||||
<value>啟用則使用 sing-box TUN ,否則使用 xray TUN</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="InvalidHttpOutboundHeaders" xml:space="preserve">
|
||||
<value>請填寫合法的HTTP請求頭JSON。</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -96,18 +96,19 @@ public partial class CoreConfigV2rayService
|
||||
var balancer = new BalancersItem4Ray
|
||||
{
|
||||
selector = [selector],
|
||||
strategy = strategyType == "leastLoad" ? new()
|
||||
strategy = new()
|
||||
{
|
||||
type = strategyType,
|
||||
settings = new()
|
||||
{
|
||||
expected = 1,
|
||||
tolerance = multipleLoad == EMultipleLoad.Fallback ? 0.2 : null,
|
||||
maxRTT = multipleLoad == EMultipleLoad.Fallback ? "5000ms" : null,
|
||||
},
|
||||
} : null,
|
||||
settings = strategyType == "leastLoad"
|
||||
? new()
|
||||
{
|
||||
expected = 1,
|
||||
tolerance = multipleLoad == EMultipleLoad.Fallback ? 0.2 : null,
|
||||
maxRTT = multipleLoad == EMultipleLoad.Fallback ? "5000ms" : null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
tag = balancerTag,
|
||||
fallbackTag = _coreConfig.outbounds?.FirstOrDefault(o => o.tag.StartsWith(selector))?.tag,
|
||||
};
|
||||
_coreConfig.routing.balancers ??= [];
|
||||
_coreConfig.routing.balancers.Add(balancer);
|
||||
|
||||
@@ -136,7 +136,6 @@ public partial class CoreConfigV2rayService
|
||||
break;
|
||||
}
|
||||
case EConfigType.SOCKS:
|
||||
case EConfigType.HTTP:
|
||||
{
|
||||
ServersItem4Ray serversItem;
|
||||
if (outbound.settings.servers.Count <= 0)
|
||||
@@ -171,6 +170,31 @@ public partial class CoreConfigV2rayService
|
||||
outbound.settings.vnext = null;
|
||||
break;
|
||||
}
|
||||
case EConfigType.HTTP:
|
||||
{
|
||||
outbound.settings.address = _node.Address;
|
||||
outbound.settings.port = _node.Port;
|
||||
|
||||
if (protocolExtra.HttpHeaders.IsNotEmpty())
|
||||
{
|
||||
outbound.settings.headers = JsonUtils.ParseJson(protocolExtra.HttpHeaders);
|
||||
}
|
||||
|
||||
if (_node.Username.IsNotEmpty()
|
||||
&& _node.Password.IsNotEmpty())
|
||||
{
|
||||
outbound.settings.user = _node.Username;
|
||||
outbound.settings.pass = _node.Password;
|
||||
outbound.settings.level = 1;
|
||||
outbound.settings.email = Global.UserEMail;
|
||||
}
|
||||
|
||||
FillOutboundMux(outbound);
|
||||
|
||||
outbound.settings.vnext = null;
|
||||
outbound.settings.servers = null;
|
||||
break;
|
||||
}
|
||||
case EConfigType.VLESS:
|
||||
{
|
||||
VnextItem4Ray vnextItem;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace ServiceLib.Services;
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
||||
ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime);
|
||||
await UpdateFunc(it.IndexId, responseTime.ToString());
|
||||
|
||||
if (responseTime > 0)
|
||||
if (!_config.UiItem.HideColumnIpInfo && responseTime > 0)
|
||||
{
|
||||
var ipInfo = await ConnectionHandler.GetIPInfo(webProxy);
|
||||
var ipStr = ipInfo?.ToString() ?? Global.None;
|
||||
|
||||
@@ -80,6 +80,9 @@ public class AddServerViewModel : MyReactiveObject
|
||||
[Reactive]
|
||||
public bool NaiveQuic { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string HttpHeadersJson { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string Hy2RealmUrl { get; set; }
|
||||
|
||||
@@ -255,7 +258,6 @@ public class AddServerViewModel : MyReactiveObject
|
||||
{
|
||||
await SaveServerAsync();
|
||||
});
|
||||
|
||||
this.WhenAnyValue(x => x.Cert)
|
||||
.Subscribe(_ => UpdateCertTip());
|
||||
|
||||
@@ -311,6 +313,7 @@ public class AddServerViewModel : MyReactiveObject
|
||||
CongestionControl = protocolExtra.CongestionControl ?? string.Empty;
|
||||
InsecureConcurrency = protocolExtra.InsecureConcurrency > 0 ? protocolExtra.InsecureConcurrency : null;
|
||||
NaiveQuic = protocolExtra.NaiveQuic ?? false;
|
||||
HttpHeadersJson = protocolExtra.HttpHeaders ?? string.Empty;
|
||||
Hy2RealmUrl = protocolExtra.Hy2RealmUrl ?? string.Empty;
|
||||
GeckoMinPacketSize = protocolExtra.GeckoMinPacketSize.ToInt();
|
||||
GeckoMaxPacketSize = protocolExtra.GeckoMaxPacketSize.ToInt();
|
||||
@@ -379,6 +382,11 @@ public class AddServerViewModel : MyReactiveObject
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (HttpHeadersJson.IsNotEmpty() && JsonUtils.ParseJson(HttpHeadersJson) == null)
|
||||
{
|
||||
NoticeManager.Instance.Enqueue(ResUI.InvalidHttpOutboundHeaders);
|
||||
return;
|
||||
}
|
||||
SelectedSource.CoreType = CoreType.IsNullOrEmpty() ? null : Enum.Parse<ECoreType>(CoreType);
|
||||
SelectedSource.AllowInsecure = AllowInsecure ? Global.StringTrue : Global.StringFalse;
|
||||
SelectedSource.MuxEnabled = MuxEnabled;
|
||||
@@ -416,6 +424,7 @@ public class AddServerViewModel : MyReactiveObject
|
||||
VmessSecurity = VmessSecurity.NullIfEmpty(),
|
||||
VlessEncryption = VlessEncryption.NullIfEmpty(),
|
||||
SsMethod = SsMethod.NullIfEmpty(),
|
||||
HttpHeaders = SelectedSource.ConfigType == EConfigType.HTTP ? HttpHeadersJson.NullIfEmpty() : null,
|
||||
WgPublicKey = WgPublicKey.NullIfEmpty(),
|
||||
WgPresharedKey = WgPresharedKey.NullIfEmpty(),
|
||||
WgInterfaceAddress = WgInterfaceAddress.NullIfEmpty(),
|
||||
|
||||
@@ -97,7 +97,7 @@ public class StatusBarViewModel : MyReactiveObject
|
||||
_config = AppManager.Instance.Config;
|
||||
SelectedRouting = new();
|
||||
SelectedServer = new();
|
||||
RunningServerToolTipText = "-";
|
||||
RunningServerToolTipText = GetRunningServerToolTipText("-");
|
||||
BlSystemProxyPacVisible = Utils.IsWindows();
|
||||
BlIsNonWindows = Utils.IsNonWindows();
|
||||
|
||||
@@ -293,16 +293,21 @@ public class StatusBarViewModel : MyReactiveObject
|
||||
var running = await ConfigHandler.GetDefaultServer(_config);
|
||||
if (running != null)
|
||||
{
|
||||
RunningServerDisplay =
|
||||
RunningServerToolTipText = running.GetSummary();
|
||||
RunningServerDisplay = running.GetSummary();
|
||||
RunningServerToolTipText = GetRunningServerToolTipText(RunningServerDisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
RunningServerDisplay =
|
||||
RunningServerToolTipText = ResUI.CheckServerSettings;
|
||||
RunningServerDisplay = ResUI.CheckServerSettings;
|
||||
RunningServerToolTipText = GetRunningServerToolTipText(RunningServerDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetRunningServerToolTipText(string serverInfo)
|
||||
{
|
||||
return Utils.IsLinux() ? Global.AppName : serverInfo;
|
||||
}
|
||||
|
||||
private async Task RefreshServersMenu()
|
||||
{
|
||||
var lstModel = await AppManager.Instance.ProfileModels(_config.SubIndexId, "");
|
||||
|
||||
@@ -256,6 +256,27 @@
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="tbHttpHeaders"
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="False"
|
||||
Text="{x:Static resx:ResUI.TbHttpOutboundHeaders}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TipHttpOutboundHeaders}" />
|
||||
<views:JsonEditor
|
||||
x:Name="txtHttpHeadersJson"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
MinHeight="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="False"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TipHttpOutboundHeaders}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridVLESS"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using v2rayN.Desktop.Base;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
@@ -54,8 +55,13 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||
break;
|
||||
|
||||
case EConfigType.SOCKS:
|
||||
gridSocks.IsVisible = true;
|
||||
break;
|
||||
|
||||
case EConfigType.HTTP:
|
||||
gridSocks.IsVisible = true;
|
||||
tbHttpHeaders.IsVisible = true;
|
||||
txtHttpHeadersJson.IsVisible = true;
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
@@ -148,9 +154,14 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||
break;
|
||||
|
||||
case EConfigType.SOCKS:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtSecurity4.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.HTTP:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtSecurity4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.HttpHeadersJson, v => v.txtHttpHeadersJson.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
|
||||
@@ -431,7 +431,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
}
|
||||
if (item.Name.Equals("IpInfo", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
item2.IsVisible = _config.SpeedTestItem.IPAPIUrl.IsNotEmpty();
|
||||
item2.IsVisible = _config.SpeedTestItem.IPAPIUrl.IsNotEmpty() && !_config.UiItem.HideColumnIpInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +349,31 @@
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="tbHttpHeaders"
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Top"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbHttpOutboundHeaders}"
|
||||
Visibility="Collapsed" />
|
||||
<TextBox
|
||||
x:Name="txtHttpHeadersJson"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TipHttpOutboundHeaders}"
|
||||
AcceptsReturn="True"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
MaxLines="8"
|
||||
MinLines="4"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="NoWrap"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="Collapsed" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridVLESS"
|
||||
|
||||
@@ -53,8 +53,13 @@ public partial class AddServerWindow
|
||||
break;
|
||||
|
||||
case EConfigType.SOCKS:
|
||||
gridSocks.Visibility = Visibility.Visible;
|
||||
break;
|
||||
|
||||
case EConfigType.HTTP:
|
||||
gridSocks.Visibility = Visibility.Visible;
|
||||
tbHttpHeaders.Visibility = Visibility.Visible;
|
||||
txtHttpHeadersJson.Visibility = Visibility.Visible;
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
@@ -147,9 +152,14 @@ public partial class AddServerWindow
|
||||
break;
|
||||
|
||||
case EConfigType.SOCKS:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtSecurity4.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.HTTP:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtSecurity4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.HttpHeadersJson, v => v.txtHttpHeadersJson.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
|
||||
@@ -384,7 +384,7 @@ public partial class ProfilesView
|
||||
}
|
||||
if (item.Name.Equals("IpInfo", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
item2.Visibility = _config.SpeedTestItem.IPAPIUrl.IsNotEmpty() ? Visibility.Visible : Visibility.Hidden;
|
||||
item2.Visibility = _config.SpeedTestItem.IPAPIUrl.IsNotEmpty() && !_config.UiItem.HideColumnIpInfo ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user