Integrate Xray 26.9.9 with the sing-box system tunnel and verify Windows routes during health checks. Improve endpoint selection, network recovery, subscription refresh deadlines, diagnostics, packaging, and regression coverage.
64 lines
3.4 KiB
C#
64 lines
3.4 KiB
C#
using System.Text;
|
|
using QVPN.Core;
|
|
|
|
public static class SubscriptionTransportTests
|
|
{
|
|
public static async Task RunAsync(Func<string, Action, Task> test)
|
|
{
|
|
await test("Subscription keeps distinct flow and fingerprint variants of one endpoint", () =>
|
|
{
|
|
var nodes = Subscription.Parse(string.Join('\n',
|
|
Link("xtls-rprx-vision", "chrome"), Link("", "chrome"),
|
|
Link("xtls-rprx-vision", "firefox"), Link("xtls-rprx-vision-udp443", "chrome")));
|
|
Check(nodes.Count == 4 && nodes.Select(n => n.Id).Distinct().Count() == 4);
|
|
Check(nodes.Select(n => (n.Flow, n.Fingerprint)).SequenceEqual(new[]
|
|
{
|
|
("xtls-rprx-vision", "chrome"), ("", "chrome"),
|
|
("xtls-rprx-vision", "firefox"), ("xtls-rprx-vision-udp443", "chrome")
|
|
}));
|
|
});
|
|
await test("Subscription presentation and parameter order do not duplicate a transport", () =>
|
|
{
|
|
var first = Link("xtls-rprx-vision", "chrome", "First location");
|
|
var same = Link("xtls-rprx-vision", "chrome", "Renamed location");
|
|
int question = same.IndexOf('?'), fragment = same.IndexOf('#');
|
|
same = same[..(question + 1)] + string.Join('&', same[(question + 1)..fragment].Split('&').Reverse()) + same[fragment..];
|
|
var nodes = Subscription.Parse(first + "\n" + same);
|
|
Check(nodes.Count == 1 && nodes[0].Name == "First location");
|
|
Check(Subscription.Parse(same).Single().Id == nodes[0].Id);
|
|
});
|
|
await test("Vision UDP443 is preserved in plain and encoded subscriptions and Xray", () =>
|
|
{
|
|
string link = Link("xtls-rprx-vision-udp443", "chrome");
|
|
foreach (string text in new[] { link, Convert.ToBase64String(Encoding.UTF8.GetBytes(link)) })
|
|
{
|
|
var node = Subscription.Parse(text).Single();
|
|
Check(node.Flow == "xtls-rprx-vision-udp443");
|
|
var user = XrayConfigBuilder.Build(node)["outbounds"]![0]!["settings"]!["vnext"]![0]!["users"]![0]!;
|
|
Check(user["flow"]!.GetValue<string>() == node.Flow);
|
|
}
|
|
});
|
|
await test("Subscription accepts only the exact supported flow names", () =>
|
|
{
|
|
foreach (string flow in new[] { "xtls-rprx-vision-udp", "xtls-rprx-vision-udp443-extra", "XTLS-rprx-vision-udp443", "xtls-rprx-vision\n" })
|
|
{
|
|
try { Subscription.Parse(Link(flow, "chrome")); }
|
|
catch (InvalidDataException) { continue; }
|
|
throw new InvalidOperationException("Unsupported subscription flow was accepted.");
|
|
}
|
|
});
|
|
}
|
|
|
|
private static string Link(string flow, string fingerprint, string name = "Synthetic location")
|
|
{
|
|
string uuid = new Guid(Enumerable.Range(1, 16).Select(i => (byte)i).ToArray()).ToString();
|
|
string key = Convert.ToBase64String(Enumerable.Range(1, 32).Select(i => (byte)i).ToArray()).TrimEnd('=').Replace('+', '-').Replace('/', '_');
|
|
return $"vless://{uuid}@8.8.8.8:443?security=reality&type=tcp&encryption=none&pbk={key}&sid=abcd&sni=example.com&fp={fingerprint}&flow={Uri.EscapeDataString(flow)}#{Uri.EscapeDataString(name)}";
|
|
}
|
|
|
|
private static void Check(bool condition)
|
|
{
|
|
if (!condition) throw new InvalidOperationException("Subscription transport regression.");
|
|
}
|
|
}
|