mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-01 01:55:00 +03:00
fix(hysteria2): emit https server_url for sing-box realm outbound (#9642)
sing-box requires realm.server_url as a full URL (https://host:port). Bare host:port caused "missing host in realm server_url" on import. Also forward stun_servers and clear ResolveRealm success message. Fixes #9635
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
using AwesomeAssertions;
|
using AwesomeAssertions;
|
||||||
using ServiceLib.Common;
|
using ServiceLib.Common;
|
||||||
using ServiceLib.Enums;
|
using ServiceLib.Enums;
|
||||||
|
using ServiceLib.Handler.Fmt;
|
||||||
using ServiceLib.Manager;
|
using ServiceLib.Manager;
|
||||||
using ServiceLib.Models;
|
using ServiceLib.Models;
|
||||||
|
using ServiceLib.Models.Dto;
|
||||||
using ServiceLib.Services.CoreConfig;
|
using ServiceLib.Services.CoreConfig;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -557,4 +559,37 @@ public class CoreConfigSingboxServiceTests
|
|||||||
cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Global));
|
cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Global));
|
||||||
cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Direct));
|
cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Direct));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GenerateClientConfigContent_Hysteria2Realm_ShouldEmitHttpsServerUrl()
|
||||||
|
{
|
||||||
|
var shareLink =
|
||||||
|
"hysteria2+realm://public@realm.hy2.io/my-realm-id?auth=uuid&stun=turn.cloudflare.com%3A3478&sni=cloudflare.com&pinSHA256=xxx#Realm-Test";
|
||||||
|
var node = Hysteria2Fmt.ResolveRealm(shareLink, out _);
|
||||||
|
node.Should().NotBeNull();
|
||||||
|
node!.CoreType = ECoreType.sing_box;
|
||||||
|
|
||||||
|
var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box);
|
||||||
|
config.CoreTypeItem =
|
||||||
|
[
|
||||||
|
new CoreTypeItem { ConfigType = EConfigType.Hysteria2, CoreType = ECoreType.sing_box }
|
||||||
|
];
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||||
|
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.sing_box);
|
||||||
|
|
||||||
|
var result = new CoreConfigSingboxService(context).GenerateClientConfigContent();
|
||||||
|
|
||||||
|
result.Success.Should().BeTrue($"ret msg: {result.Msg}");
|
||||||
|
var cfg = JsonUtils.Deserialize<SingboxConfig>(result.Data!.ToString())!;
|
||||||
|
var proxy = cfg.outbounds.First(o => o.tag == Global.ProxyTag);
|
||||||
|
|
||||||
|
proxy.type.Should().Be("hysteria2");
|
||||||
|
proxy.realm.Should().NotBeNull();
|
||||||
|
proxy.realm!.server_url.Should().StartWith("https://");
|
||||||
|
proxy.realm.server_url.Should().Contain("realm.hy2.io");
|
||||||
|
proxy.realm.token.Should().Be("public");
|
||||||
|
proxy.realm.realm_id.Should().Be("my-realm-id");
|
||||||
|
proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478");
|
||||||
|
proxy.server.Should().BeNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using AwesomeAssertions;
|
using AwesomeAssertions;
|
||||||
|
using ServiceLib.Handler.Fmt;
|
||||||
|
using ServiceLib.Models.Dto;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace ServiceLib.Tests.Fmt;
|
namespace ServiceLib.Tests.Fmt;
|
||||||
@@ -58,4 +60,32 @@ public class HyRealmTests
|
|||||||
uri.Should().Contain("hysteria2+realm://mytoken@rendezvous.example.com");
|
uri.Should().Contain("hysteria2+realm://mytoken@rendezvous.example.com");
|
||||||
uri.Should().EndWith("#remark");
|
uri.Should().EndWith("#remark");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToServerUrl_ShouldIncludeSchemeForSingbox()
|
||||||
|
{
|
||||||
|
var realm = new HyRealm(
|
||||||
|
IsHttp: false,
|
||||||
|
Token: "public",
|
||||||
|
RendezvousHost: "realm.hy2.io",
|
||||||
|
RendezvousPort: 443,
|
||||||
|
RealmName: "my-realm-id",
|
||||||
|
StunList: ["turn.cloudflare.com:3478"]
|
||||||
|
);
|
||||||
|
|
||||||
|
realm.ToServerUrl().Should().Be("https://realm.hy2.io:443");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResolveRealm_Issue9635_ShouldProduceHttpsServerUrl()
|
||||||
|
{
|
||||||
|
var str = "hysteria2+realm://public@realm.hy2.io/my-realm-id?auth=uuid&stun=turn.cloudflare.com%3A3478&sni=cloudflare.com&pinSHA256=xxx#Realm-Test";
|
||||||
|
var resolved = Hysteria2Fmt.ResolveRealm(str, out _);
|
||||||
|
resolved.Should().NotBeNull();
|
||||||
|
|
||||||
|
HyRealm.TryParse(resolved!.GetProtocolExtra().Hy2RealmUrl, out var realm).Should().BeTrue();
|
||||||
|
realm!.ToServerUrl().Should().StartWith("https://");
|
||||||
|
realm.ToServerUrl().Should().Contain("realm.hy2.io");
|
||||||
|
realm.StunList.Should().Contain("turn.cloudflare.com:3478");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ public class Hysteria2Fmt : BaseFmt
|
|||||||
Hy2RealmUrl = realm.ToUri(),
|
Hy2RealmUrl = realm.ToUri(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
msg = string.Empty;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ public class HyRealm4Sbox
|
|||||||
public string? server_url { get; set; }
|
public string? server_url { get; set; }
|
||||||
public string? token { get; set; }
|
public string? token { get; set; }
|
||||||
public string? realm_id { get; set; }
|
public string? realm_id { get; set; }
|
||||||
|
public List<string>? stun_servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Server4Sbox : BaseServer4Sbox
|
public class Server4Sbox : BaseServer4Sbox
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ public record HyRealm(
|
|||||||
{
|
{
|
||||||
public string RendezvousHostPort => RendezvousPort > 0 ? $"{RendezvousHost}:{RendezvousPort}" : RendezvousHost;
|
public string RendezvousHostPort => RendezvousPort > 0 ? $"{RendezvousHost}:{RendezvousPort}" : RendezvousHost;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sing-box realm.server_url requires a scheme (https:// or http://).
|
||||||
|
/// </summary>
|
||||||
|
public string ToServerUrl()
|
||||||
|
{
|
||||||
|
var scheme = IsHttp ? "http" : "https";
|
||||||
|
return $"{scheme}://{RendezvousHostPort}";
|
||||||
|
}
|
||||||
|
|
||||||
public static bool TryParse(string? str, out HyRealm? realm)
|
public static bool TryParse(string? str, out HyRealm? realm)
|
||||||
{
|
{
|
||||||
realm = null;
|
realm = null;
|
||||||
|
|||||||
@@ -275,9 +275,10 @@ public partial class CoreConfigSingboxService
|
|||||||
{
|
{
|
||||||
var realm4Sbox = new HyRealm4Sbox()
|
var realm4Sbox = new HyRealm4Sbox()
|
||||||
{
|
{
|
||||||
server_url = realm.RendezvousHostPort,
|
server_url = realm.ToServerUrl(),
|
||||||
token = realm.Token,
|
token = realm.Token,
|
||||||
realm_id = realm.RealmName,
|
realm_id = realm.RealmName,
|
||||||
|
stun_servers = realm.StunList?.Count > 0 ? realm.StunList : null,
|
||||||
};
|
};
|
||||||
outbound.realm = realm4Sbox;
|
outbound.realm = realm4Sbox;
|
||||||
outbound.server = null;
|
outbound.server = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user