diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index e1daa015..e7a2cd27 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -170,7 +170,11 @@ public class Global { EConfigType.Hysteria2, "hysteria2://" }, { EConfigType.TUIC, "tuic://" }, { EConfigType.WireGuard, "wireguard://" }, - { EConfigType.Anytls, "anytls://" } + { EConfigType.Anytls, "anytls://" }, + { EConfigType.NaiveProxy, "naive://" }, + { EConfigType.Juicity, "juicity://" }, + { EConfigType.Brook, "brook://" }, + { EConfigType.Shadowquic, "shadowquic://" } }; public static readonly Dictionary ProtocolTypes = new() @@ -184,7 +188,11 @@ public class Global { EConfigType.Hysteria2, "hysteria2" }, { EConfigType.TUIC, "tuic" }, { EConfigType.WireGuard, "wireguard" }, - { EConfigType.Anytls, "anytls" } + { EConfigType.Anytls, "anytls" }, + { EConfigType.NaiveProxy, "naiveproxy" }, + { EConfigType.Juicity, "juicity" }, + { EConfigType.Brook, "brook" }, + { EConfigType.Shadowquic, "shadowquic" } }; public static readonly List VmessSecurities = diff --git a/v2rayN/ServiceLib/Handler/Fmt/BrookFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/BrookFmt.cs new file mode 100644 index 00000000..4bde23b5 --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/BrookFmt.cs @@ -0,0 +1,49 @@ +using static QRCoder.PayloadGenerator; + +namespace ServiceLib.Handler.Fmt; +public class BrookFmt : BaseFmt +{ + public static ProfileItem? Resolve(string str, out string msg) + { + msg = ResUI.ConfigurationFormatIncorrect; + + var parsedUrl = Utils.TryUri(str); + if (parsedUrl == null) + { + return null; + } + + ProfileItem item = new() + { + ConfigType = EConfigType.Brook, + Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), + Address = parsedUrl.IdnHost, + Port = parsedUrl.Port, + }; + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); + item.Id = rawUserInfo; + + var query = Utils.ParseQueryString(parsedUrl.Query); + _ = ResolveStdTransport(query, ref item); + + return item; + } + + public static string? ToUri(ProfileItem? item) + { + if (item == null) + { + return null; + } + var remark = string.Empty; + if (item.Remarks.IsNotEmpty()) + { + remark = "#" + Utils.UrlEncode(item.Remarks); + } + var pw = item.Id; + var dicQuery = new Dictionary(); + _ = GetStdTransport(item, Global.None, ref dicQuery); + + return ToUri(EConfigType.Brook, item.Address, item.Port, pw, dicQuery, remark); + } +} diff --git a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs index 814d753d..41e112ff 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs @@ -19,6 +19,10 @@ public class FmtHandler EConfigType.TUIC => TuicFmt.ToUri(item), EConfigType.WireGuard => WireguardFmt.ToUri(item), EConfigType.Anytls => AnytlsFmt.ToUri(item), + EConfigType.NaiveProxy => NaiveFmt.ToUri(item), + EConfigType.Juicity => JuicityFmt.ToUri(item), + EConfigType.Brook => BrookFmt.ToUri(item), + EConfigType.Shadowquic => ShadowquicFmt.ToUri(item), _ => null, }; @@ -80,6 +84,22 @@ public class FmtHandler { return AnytlsFmt.Resolve(str, out msg); } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.NaiveProxy])) + { + return NaiveFmt.Resolve(str, out msg); + } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.Juicity])) + { + return JuicityFmt.Resolve(str, out msg); + } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.Brook])) + { + return BrookFmt.Resolve(str, out msg); + } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowquic])) + { + return ShadowquicFmt.Resolve(str, out msg); + } else { msg = ResUI.NonvmessOrssProtocol; diff --git a/v2rayN/ServiceLib/Handler/Fmt/JuicityFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/JuicityFmt.cs new file mode 100644 index 00000000..d6cda203 --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/JuicityFmt.cs @@ -0,0 +1,63 @@ +namespace ServiceLib.Handler.Fmt; + +public class JuicityFmt : BaseFmt +{ + public static ProfileItem? Resolve(string str, out string msg) + { + msg = ResUI.ConfigurationFormatIncorrect; + + ProfileItem item = new() + { + ConfigType = EConfigType.Juicity + }; + + var url = Utils.TryUri(str); + if (url == null) + { + return null; + } + + item.Address = url.IdnHost; + item.Port = url.Port; + item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); + var rawUserInfo = Utils.UrlDecode(url.UserInfo); + var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); + if (userInfoParts.Length == 2) + { + item.Id = userInfoParts.First(); + item.Security = userInfoParts.Last(); + } + + var query = Utils.ParseQueryString(url.Query); + ResolveStdTransport(query, ref item); + item.HeaderType = query["congestion_control"] ?? ""; + + return item; + } + + public static string? ToUri(ProfileItem? item) + { + if (item == null) + { + return null; + } + + var remark = string.Empty; + if (item.Remarks.IsNotEmpty()) + { + remark = "#" + Utils.UrlEncode(item.Remarks); + } + var dicQuery = new Dictionary(); + if (item.Sni.IsNotEmpty()) + { + dicQuery.Add("sni", item.Sni); + } + if (item.Alpn.IsNotEmpty()) + { + dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn)); + } + dicQuery.Add("congestion_control", item.HeaderType); + + return ToUri(EConfigType.Juicity, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark); + } +} diff --git a/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs new file mode 100644 index 00000000..95c5583d --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs @@ -0,0 +1,52 @@ +using static QRCoder.PayloadGenerator; + +namespace ServiceLib.Handler.Fmt; +public class NaiveFmt : BaseFmt +{ + public static ProfileItem? Resolve(string str, out string msg) + { + msg = ResUI.ConfigurationFormatIncorrect; + + var parsedUrl = Utils.TryUri(str); + if (parsedUrl == null) + { + return null; + } + + ProfileItem item = new() + { + ConfigType = EConfigType.NaiveProxy, + Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), + Address = parsedUrl.IdnHost, + Port = parsedUrl.Port, + }; + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); + item.Id = rawUserInfo; + + var query = Utils.ParseQueryString(parsedUrl.Query); + _ = ResolveStdTransport(query, ref item); + + item.HeaderType = query["protocol"] ?? ""; + + return item; + } + + public static string? ToUri(ProfileItem? item) + { + if (item == null) + { + return null; + } + var remark = string.Empty; + if (item.Remarks.IsNotEmpty()) + { + remark = "#" + Utils.UrlEncode(item.Remarks); + } + var pw = item.Id; + var dicQuery = new Dictionary(); + _ = GetStdTransport(item, Global.None, ref dicQuery); + dicQuery.Add("protocol", item.HeaderType); + + return ToUri(EConfigType.NaiveProxy, item.Address, item.Port, pw, dicQuery, remark); + } +} diff --git a/v2rayN/ServiceLib/Handler/Fmt/ShadowquicFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/ShadowquicFmt.cs new file mode 100644 index 00000000..468923da --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/ShadowquicFmt.cs @@ -0,0 +1,63 @@ +namespace ServiceLib.Handler.Fmt; + +public class ShadowquicFmt : BaseFmt +{ + public static ProfileItem? Resolve(string str, out string msg) + { + msg = ResUI.ConfigurationFormatIncorrect; + + ProfileItem item = new() + { + ConfigType = EConfigType.Shadowquic + }; + + var url = Utils.TryUri(str); + if (url == null) + { + return null; + } + + item.Address = url.IdnHost; + item.Port = url.Port; + item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); + var rawUserInfo = Utils.UrlDecode(url.UserInfo); + var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); + if (userInfoParts.Length == 2) + { + item.Id = userInfoParts.First(); + item.Security = userInfoParts.Last(); + } + + var query = Utils.ParseQueryString(url.Query); + ResolveStdTransport(query, ref item); + item.HeaderType = query["congestion_control"] ?? ""; + + return item; + } + + public static string? ToUri(ProfileItem? item) + { + if (item == null) + { + return null; + } + + var remark = string.Empty; + if (item.Remarks.IsNotEmpty()) + { + remark = "#" + Utils.UrlEncode(item.Remarks); + } + var dicQuery = new Dictionary(); + if (item.Sni.IsNotEmpty()) + { + dicQuery.Add("sni", item.Sni); + } + if (item.Alpn.IsNotEmpty()) + { + dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn)); + } + dicQuery.Add("congestion_control", item.HeaderType); + + return ToUri(EConfigType.Shadowquic, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark); + } +}