Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e30c55a0af | ||
|
|
b583590a64 | ||
|
|
a28c63168a | ||
|
|
620422350f | ||
|
|
b77cc3c33b | ||
|
|
71bf9b4887 | ||
|
|
9039d401da | ||
|
|
74a0a93201 | ||
|
|
522571f0b3 | ||
|
|
123c49c22d | ||
|
|
1ff88d29be | ||
|
|
63d5a2a1be | ||
|
|
1e9a6cb06b | ||
|
|
31748aa660 | ||
|
|
d0c6ea6a63 | ||
|
|
7ffe286a56 | ||
|
|
b99b30163b | ||
|
|
83b4f1e660 |
@@ -9,9 +9,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.63.0">
|
||||
<PackageReference Include="Google.Protobuf" Version="3.27.1" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.64.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -58,10 +58,12 @@ namespace v2rayN
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
}
|
||||
//if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
|
||||
//{
|
||||
// _config.guiItem.enableStatistics = false;
|
||||
//}
|
||||
|
||||
//Under Win10
|
||||
if (Environment.OSVersion.Version.Major < 10)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
|
||||
}
|
||||
}
|
||||
|
||||
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
|
||||
@@ -105,9 +105,12 @@ namespace v2rayN
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="nullValue"></param>
|
||||
/// <returns></returns>
|
||||
public static int ToFile(object? obj, string filePath, bool nullValue = true)
|
||||
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
|
||||
{
|
||||
int result;
|
||||
if (filePath is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
using FileStream file = File.Create(filePath);
|
||||
@@ -119,14 +122,13 @@ namespace v2rayN
|
||||
};
|
||||
|
||||
JsonSerializer.Serialize(file, obj, options);
|
||||
result = 0;
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
result = -1;
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using QRCoder;
|
||||
using QRCoder.Xaml;
|
||||
using System.Drawing;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using ZXing;
|
||||
using ZXing.Common;
|
||||
using ZXing.QrCode;
|
||||
using ZXing.Windows.Compatibility;
|
||||
using ZXing;
|
||||
|
||||
namespace v2rayN
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace v2rayN
|
||||
/// </summary>
|
||||
/// <param name="lst"></param>
|
||||
/// <returns></returns>
|
||||
public static string List2String(List<string> lst, bool wrap = false)
|
||||
public static string List2String(List<string>? lst, bool wrap = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1084,8 +1084,10 @@ namespace v2rayN
|
||||
{
|
||||
try
|
||||
{
|
||||
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
|
||||
var guid = new Guid(sum);
|
||||
string pnputilPath = @"C:\Windows\System32\pnputil.exe";
|
||||
string arg = $" /remove-device /deviceid \"wintun\"";
|
||||
string arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
|
||||
|
||||
// Try to remove the device
|
||||
Process proc = new()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EConfigType
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum ECoreType
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EGlobalHotkey
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EInboundProtocol
|
||||
{
|
||||
@@ -8,6 +8,7 @@
|
||||
http2,
|
||||
pac,
|
||||
api,
|
||||
api2,
|
||||
speedtest = 21
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EMove
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EServerColName
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum ESpeedActionType
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum ESysProxyType
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum ETransport
|
||||
{
|
||||
@@ -6,6 +6,7 @@
|
||||
kcp,
|
||||
ws,
|
||||
httpupgrade,
|
||||
splithttp,
|
||||
h2,
|
||||
http,
|
||||
quic,
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace v2rayN.Models
|
||||
namespace v2rayN.Enums
|
||||
{
|
||||
public enum EViewAction
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN
|
||||
{
|
||||
@@ -23,7 +23,8 @@ namespace v2rayN
|
||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/SagerNet/sing-{0}/rule-set/{1}.srs";
|
||||
public const string SingboxRulesetUrlGeosite = @"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-{0}.srs";
|
||||
public const string SingboxRulesetUrlGeoip = @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/srs/{0}.srs";
|
||||
|
||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||
public const string ConfigFileName = "guiNConfig.json";
|
||||
@@ -106,7 +107,6 @@ namespace v2rayN
|
||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||
@"http://cachefly.cachefly.net/50mb.test",
|
||||
@"http://cachefly.cachefly.net/100mb.test",
|
||||
@"http://cachefly.cachefly.net/10mb.test"
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace v2rayN
|
||||
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
|
||||
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "h2", "quic", "grpc" };
|
||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
|
||||
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||
public static readonly List<string> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
|
||||
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
||||
@@ -175,6 +175,7 @@ namespace v2rayN
|
||||
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
||||
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
|
||||
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
||||
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler.Fmt;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
@@ -1069,12 +1072,12 @@ namespace v2rayN.Handler
|
||||
/// 批量添加服务器
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="clipboardData"></param>
|
||||
/// <param name="strData"></param>
|
||||
/// <param name="subid"></param>
|
||||
/// <returns>成功导入的数量</returns>
|
||||
private static int AddBatchServers(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
private static int AddBatchServers(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(clipboardData))
|
||||
if (Utils.IsNullOrEmpty(strData))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -1091,7 +1094,7 @@ namespace v2rayN.Handler
|
||||
//Check for duplicate indexId
|
||||
List<string>? lstDbIndexId = null;
|
||||
List<ProfileItem> lstAdd = new();
|
||||
var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
|
||||
var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
|
||||
if (isSub)
|
||||
{
|
||||
arrData = arrData.Distinct();
|
||||
@@ -1107,7 +1110,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
continue;
|
||||
}
|
||||
var profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg);
|
||||
var profileItem = FmtHandler.ResolveConfig(str, out string msg);
|
||||
if (profileItem is null)
|
||||
{
|
||||
continue;
|
||||
@@ -1176,55 +1179,39 @@ namespace v2rayN.Handler
|
||||
return countServers;
|
||||
}
|
||||
|
||||
private static int AddBatchServers4Custom(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
private static int AddBatchServers4Custom(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(clipboardData))
|
||||
if (Utils.IsNullOrEmpty(strData))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var subRemarks = LazyConfig.Instance.GetSubItem(subid)?.remarks;
|
||||
|
||||
//判断str是否包含s的任意一个字符串
|
||||
static bool Contains(string str, params string[] s)
|
||||
List<ProfileItem>? lstProfiles = null;
|
||||
//Is sing-box array configuration
|
||||
if (lstProfiles is null || lstProfiles.Count <= 0)
|
||||
{
|
||||
foreach (var item in s)
|
||||
{
|
||||
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
||||
}
|
||||
return false;
|
||||
lstProfiles = SingboxFmt.ResolveFullArray(strData, subRemarks);
|
||||
}
|
||||
|
||||
//Is v2ray array configuration
|
||||
var configObjects = JsonUtils.Deserialize<Object[]>(clipboardData);
|
||||
if (configObjects != null && configObjects.Length > 0)
|
||||
if (lstProfiles is null || lstProfiles.Count <= 0)
|
||||
{
|
||||
lstProfiles = V2rayFmt.ResolveFullArray(strData, subRemarks);
|
||||
}
|
||||
if (lstProfiles != null && lstProfiles.Count > 0)
|
||||
{
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
{
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
foreach (var configObject in configObjects)
|
||||
foreach (var it in lstProfiles)
|
||||
{
|
||||
var objectString = JsonUtils.Serialize(configObject);
|
||||
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
|
||||
if (v2rayCon?.inbounds?.Count > 0 && v2rayCon.outbounds?.Count > 0)
|
||||
it.subid = subid;
|
||||
it.isSub = isSub;
|
||||
if (AddCustomServer(config, it, true) == 0)
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, objectString);
|
||||
|
||||
var profileIt = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.Xray,
|
||||
address = fileName,
|
||||
remarks = v2rayCon.remarks ?? "v2ray_custom",
|
||||
subid = subid,
|
||||
isSub = isSub
|
||||
};
|
||||
|
||||
if (AddCustomServer(config, profileIt, true) == 0)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0)
|
||||
@@ -1233,58 +1220,39 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
|
||||
ProfileItem profileItem = new();
|
||||
//Is v2ray configuration
|
||||
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(clipboardData);
|
||||
if (v2rayConfig?.inbounds?.Count > 0
|
||||
&& v2rayConfig.outbounds?.Count > 0)
|
||||
ProfileItem? profileItem = null;
|
||||
//Is sing-box configuration
|
||||
if (profileItem is null)
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
|
||||
profileItem.coreType = ECoreType.Xray;
|
||||
profileItem.address = fileName;
|
||||
profileItem.remarks = v2rayConfig.remarks ?? "v2ray_custom";
|
||||
profileItem = SingboxFmt.ResolveFull(strData, subRemarks);
|
||||
}
|
||||
//Is v2ray configuration
|
||||
if (profileItem is null)
|
||||
{
|
||||
profileItem = V2rayFmt.ResolveFull(strData, subRemarks);
|
||||
}
|
||||
//Is Clash configuration
|
||||
else if (Contains(clipboardData, "port", "socks-port", "proxies"))
|
||||
if (profileItem is null)
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
|
||||
profileItem.coreType = ECoreType.mihomo;
|
||||
profileItem.address = fileName;
|
||||
profileItem.remarks = "clash_custom";
|
||||
profileItem = ClashFmt.ResolveFull(strData, subRemarks);
|
||||
}
|
||||
//Is hysteria configuration
|
||||
else if (Contains(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
|
||||
if (profileItem is null)
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
|
||||
profileItem.coreType = ECoreType.hysteria;
|
||||
profileItem.address = fileName;
|
||||
profileItem.remarks = "hysteria_custom";
|
||||
profileItem = Hysteria2Fmt.ResolveFull2(strData, subRemarks);
|
||||
}
|
||||
if (profileItem is null)
|
||||
{
|
||||
profileItem = Hysteria2Fmt.ResolveFull(strData, subRemarks);
|
||||
}
|
||||
//Is naiveproxy configuration
|
||||
else if (Contains(clipboardData, "listen", "proxy", "<html>", "<body>"))
|
||||
if (profileItem is null)
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
|
||||
profileItem.coreType = ECoreType.naiveproxy;
|
||||
profileItem.address = fileName;
|
||||
profileItem.remarks = "naiveproxy_custom";
|
||||
profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
|
||||
}
|
||||
//Is Other configuration
|
||||
else
|
||||
if (profileItem is null || Utils.IsNullOrEmpty(profileItem.address))
|
||||
{
|
||||
return -1;
|
||||
//var fileName = Utile.GetTempPath($"{Utile.GetGUID(false)}.txt");
|
||||
//File.WriteAllText(fileName, clipboardData);
|
||||
|
||||
//profileItem.address = fileName;
|
||||
//profileItem.remarks = "other_custom";
|
||||
}
|
||||
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
@@ -1297,12 +1265,6 @@ namespace v2rayN.Handler
|
||||
}
|
||||
profileItem.subid = subid;
|
||||
profileItem.isSub = isSub;
|
||||
|
||||
if (Utils.IsNullOrEmpty(profileItem.address))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (AddCustomServer(config, profileItem, true) == 0)
|
||||
{
|
||||
return 1;
|
||||
@@ -1313,9 +1275,9 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
|
||||
private static int AddBatchServers4SsSIP008(Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
private static int AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(clipboardData))
|
||||
if (Utils.IsNullOrEmpty(strData))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -1325,31 +1287,12 @@ namespace v2rayN.Handler
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
}
|
||||
|
||||
//SsSIP008
|
||||
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(clipboardData);
|
||||
if (lstSsServer?.Count <= 0)
|
||||
{
|
||||
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(clipboardData);
|
||||
if (ssSIP008?.servers?.Count > 0)
|
||||
{
|
||||
lstSsServer = ssSIP008.servers;
|
||||
}
|
||||
}
|
||||
|
||||
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
||||
if (lstSsServer?.Count > 0)
|
||||
{
|
||||
int counter = 0;
|
||||
foreach (var it in lstSsServer)
|
||||
foreach (var ssItem in lstSsServer)
|
||||
{
|
||||
var ssItem = new ProfileItem()
|
||||
{
|
||||
subid = subid,
|
||||
remarks = it.remarks,
|
||||
security = it.method,
|
||||
id = it.password,
|
||||
address = it.server,
|
||||
port = Utils.ToInt(it.server_port)
|
||||
};
|
||||
ssItem.subid = subid;
|
||||
ssItem.isSub = isSub;
|
||||
if (AddShadowsocksServer(config, ssItem) == 0)
|
||||
@@ -1364,7 +1307,7 @@ namespace v2rayN.Handler
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int AddBatchServers(Config config, string clipboardData, string subid, bool isSub)
|
||||
public static int AddBatchServers(Config config, string strData, string subid, bool isSub)
|
||||
{
|
||||
List<ProfileItem>? lstOriSub = null;
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
@@ -1373,28 +1316,28 @@ namespace v2rayN.Handler
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
if (Utils.IsBase64String(clipboardData))
|
||||
if (Utils.IsBase64String(strData))
|
||||
{
|
||||
counter = AddBatchServers(config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
|
||||
counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
|
||||
}
|
||||
if (counter < 1)
|
||||
{
|
||||
counter = AddBatchServers(config, clipboardData, subid, isSub, lstOriSub);
|
||||
counter = AddBatchServers(config, strData, subid, isSub, lstOriSub);
|
||||
}
|
||||
if (counter < 1)
|
||||
{
|
||||
counter = AddBatchServers(config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
|
||||
counter = AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub);
|
||||
}
|
||||
|
||||
if (counter < 1)
|
||||
{
|
||||
counter = AddBatchServers4SsSIP008(config, clipboardData, subid, isSub, lstOriSub);
|
||||
counter = AddBatchServers4SsSIP008(config, strData, subid, isSub, lstOriSub);
|
||||
}
|
||||
|
||||
//maybe other sub
|
||||
if (counter < 1)
|
||||
{
|
||||
counter = AddBatchServers4Custom(config, clipboardData, subid, isSub, lstOriSub);
|
||||
counter = AddBatchServers4Custom(config, strData, subid, isSub, lstOriSub);
|
||||
}
|
||||
|
||||
return counter;
|
||||
@@ -1413,18 +1356,27 @@ namespace v2rayN.Handler
|
||||
public static int AddSubItem(Config config, string url)
|
||||
{
|
||||
//already exists
|
||||
if (SQLiteHelper.Instance.Table<SubItem>().Where(e => e.url == url).Count() > 0)
|
||||
if (SQLiteHelper.Instance.Table<SubItem>().Any(e => e.url == url))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SubItem subItem = new()
|
||||
{
|
||||
id = string.Empty,
|
||||
remarks = "import_sub",
|
||||
url = url
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var queryVars = HttpUtility.ParseQueryString(uri.Query);
|
||||
subItem.remarks = queryVars["remarks"] ?? "import_sub";
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return AddSubItem(config, subItem);
|
||||
}
|
||||
|
||||
@@ -1532,16 +1484,16 @@ namespace v2rayN.Handler
|
||||
/// AddBatchRoutingRules
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="clipboardData"></param>
|
||||
/// <param name="strData"></param>
|
||||
/// <returns></returns>
|
||||
public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData)
|
||||
public static int AddBatchRoutingRules(ref RoutingItem routingItem, string strData)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(clipboardData))
|
||||
if (Utils.IsNullOrEmpty(strData))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var lstRules = JsonUtils.Deserialize<List<RulesItem>>(clipboardData);
|
||||
var lstRules = JsonUtils.Deserialize<List<RulesItem>>(strData);
|
||||
if (lstRules == null)
|
||||
{
|
||||
return -1;
|
||||
@@ -1673,7 +1625,7 @@ namespace v2rayN.Handler
|
||||
|
||||
public static int InitBuiltinRouting(Config config, bool blImportAdvancedRules = false)
|
||||
{
|
||||
var ver = "V2-";
|
||||
var ver = "V3-";
|
||||
var items = LazyConfig.Instance.RoutingItems();
|
||||
if (blImportAdvancedRules || items.Where(t => t.remarks.StartsWith(ver)).ToList().Count <= 0)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.IO;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
namespace v2rayN.Handler.CoreConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Core configuration file processing class
|
||||
@@ -26,7 +27,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return GenerateClientCustomConfig(node, fileName, out msg);
|
||||
}
|
||||
else if (config.tunModeItem.enableTun || LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
||||
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
||||
{
|
||||
var configGenSingbox = new CoreConfigSingbox(config);
|
||||
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||
@@ -154,7 +155,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
if (coreType == ECoreType.sing_box)
|
||||
{
|
||||
if ((new CoreConfigSingbox(config)).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||
if (new CoreConfigSingbox(config).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -162,7 +163,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((new CoreConfigV2ray(config)).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||
if (new CoreConfigV2ray(config).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
namespace v2rayN.Handler.CoreConfig
|
||||
{
|
||||
internal class CoreConfigSingbox
|
||||
{
|
||||
@@ -25,6 +26,11 @@ namespace v2rayN.Handler
|
||||
msg = ResUI.CheckServerSettings;
|
||||
return -1;
|
||||
}
|
||||
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp))
|
||||
{
|
||||
msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = ResUI.InitialConfiguration;
|
||||
|
||||
@@ -114,7 +120,8 @@ namespace v2rayN.Handler
|
||||
var listen = "::";
|
||||
singboxConfig.inbounds = [];
|
||||
|
||||
if (!_config.tunModeItem.enableTun || (_config.tunModeItem.enableTun && _config.tunModeItem.enableExInbound))
|
||||
if (!_config.tunModeItem.enableTun
|
||||
|| (_config.tunModeItem.enableTun && _config.tunModeItem.enableExInbound && _config.runningCoreType == ECoreType.sing_box))
|
||||
{
|
||||
var inbound = new Inbound4Sbox()
|
||||
{
|
||||
@@ -185,7 +192,7 @@ namespace v2rayN.Handler
|
||||
tunInbound.strict_route = _config.tunModeItem.strictRoute;
|
||||
tunInbound.stack = _config.tunModeItem.stack;
|
||||
tunInbound.sniff = _config.inbound[0].sniffingEnabled;
|
||||
tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
|
||||
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
|
||||
if (_config.tunModeItem.enableIPv6Address == false)
|
||||
{
|
||||
tunInbound.inet6_address = null;
|
||||
@@ -546,7 +553,7 @@ namespace v2rayN.Handler
|
||||
singboxConfig.route.rules.Add(new()
|
||||
{
|
||||
port = [53],
|
||||
network = "udp",
|
||||
network = ["udp"],
|
||||
outbound = dnsOutbound
|
||||
});
|
||||
}
|
||||
@@ -662,6 +669,10 @@ namespace v2rayN.Handler
|
||||
rule.port = new List<int> { Utils.ToInt(item.port) };
|
||||
}
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.network))
|
||||
{
|
||||
rule.network = Utils.String2List(item.network);
|
||||
}
|
||||
if (item.protocol?.Count > 0)
|
||||
{
|
||||
rule.protocol = item.protocol;
|
||||
@@ -834,14 +845,16 @@ namespace v2rayN.Handler
|
||||
.ToList();
|
||||
if (lstDomain != null && lstDomain.Count > 0)
|
||||
{
|
||||
//var strategy = dns4Sbox.servers.Where(t => !Utils.IsNullOrEmpty(t.strategy)).Select(t => t.strategy).FirstOrDefault();
|
||||
var tag = "local_local";
|
||||
dns4Sbox.servers.Insert(0, new()
|
||||
dns4Sbox.servers.Add(new()
|
||||
{
|
||||
tag = tag,
|
||||
address = "223.5.5.5",
|
||||
detour = Global.DirectTag,
|
||||
//strategy = strategy
|
||||
});
|
||||
dns4Sbox.rules.Insert(0, new()
|
||||
dns4Sbox.rules.Add(new()
|
||||
{
|
||||
server = tag,
|
||||
domain = lstDomain
|
||||
@@ -858,7 +871,7 @@ namespace v2rayN.Handler
|
||||
singboxConfig.experimental ??= new Experimental4Sbox();
|
||||
singboxConfig.experimental.clash_api = new Clash_Api4Sbox()
|
||||
{
|
||||
external_controller = $"{Global.Loopback}:{LazyConfig.Instance.StatePort}",
|
||||
external_controller = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -940,12 +953,14 @@ namespace v2rayN.Handler
|
||||
}
|
||||
else
|
||||
{
|
||||
var geo = item.Split('-').FirstOrDefault() ?? geosite;
|
||||
var value = item.Split('-').LastOrDefault();
|
||||
singboxConfig.route.rule_set.Add(new()
|
||||
{
|
||||
type = "remote",
|
||||
format = "binary",
|
||||
tag = item,
|
||||
url = string.Format(Global.SingboxRulesetUrl, item.StartsWith(geosite) ? geosite : geoip, item),
|
||||
url = string.Format(geo.Equals(geosite) ? Global.SingboxRulesetUrlGeosite : Global.SingboxRulesetUrlGeoip, value),
|
||||
download_detour = Global.ProxyTag
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
namespace v2rayN.Handler.CoreConfig
|
||||
{
|
||||
internal class CoreConfigV2ray
|
||||
{
|
||||
@@ -219,39 +220,43 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int GenRoutingUserRule(RulesItem4Ray? rules, V2rayConfig v2rayConfig)
|
||||
private int GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (rules == null)
|
||||
if (rule == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(rules.port))
|
||||
if (Utils.IsNullOrEmpty(rule.port))
|
||||
{
|
||||
rules.port = null;
|
||||
rule.port = null;
|
||||
}
|
||||
if (rules.domain?.Count == 0)
|
||||
if (Utils.IsNullOrEmpty(rule.network))
|
||||
{
|
||||
rules.domain = null;
|
||||
rule.network = null;
|
||||
}
|
||||
if (rules.ip?.Count == 0)
|
||||
if (rule.domain?.Count == 0)
|
||||
{
|
||||
rules.ip = null;
|
||||
rule.domain = null;
|
||||
}
|
||||
if (rules.protocol?.Count == 0)
|
||||
if (rule.ip?.Count == 0)
|
||||
{
|
||||
rules.protocol = null;
|
||||
rule.ip = null;
|
||||
}
|
||||
if (rules.inboundTag?.Count == 0)
|
||||
if (rule.protocol?.Count == 0)
|
||||
{
|
||||
rules.inboundTag = null;
|
||||
rule.protocol = null;
|
||||
}
|
||||
if (rule.inboundTag?.Count == 0)
|
||||
{
|
||||
rule.inboundTag = null;
|
||||
}
|
||||
|
||||
var hasDomainIp = false;
|
||||
if (rules.domain?.Count > 0)
|
||||
if (rule.domain?.Count > 0)
|
||||
{
|
||||
var it = JsonUtils.DeepCopy(rules);
|
||||
var it = JsonUtils.DeepCopy(rule);
|
||||
it.ip = null;
|
||||
it.type = "field";
|
||||
for (int k = it.domain.Count - 1; k >= 0; k--)
|
||||
@@ -265,9 +270,9 @@ namespace v2rayN.Handler
|
||||
v2rayConfig.routing.rules.Add(it);
|
||||
hasDomainIp = true;
|
||||
}
|
||||
if (rules.ip?.Count > 0)
|
||||
if (rule.ip?.Count > 0)
|
||||
{
|
||||
var it = JsonUtils.DeepCopy(rules);
|
||||
var it = JsonUtils.DeepCopy(rule);
|
||||
it.domain = null;
|
||||
it.type = "field";
|
||||
v2rayConfig.routing.rules.Add(it);
|
||||
@@ -275,12 +280,12 @@ namespace v2rayN.Handler
|
||||
}
|
||||
if (!hasDomainIp)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(rules.port)
|
||||
|| (rules.protocol?.Count > 0)
|
||||
|| (rules.inboundTag?.Count > 0)
|
||||
if (!Utils.IsNullOrEmpty(rule.port)
|
||||
|| rule.protocol?.Count > 0
|
||||
|| rule.inboundTag?.Count > 0
|
||||
)
|
||||
{
|
||||
var it = JsonUtils.DeepCopy(rules);
|
||||
var it = JsonUtils.DeepCopy(rule);
|
||||
it.type = "field";
|
||||
v2rayConfig.routing.rules.Add(it);
|
||||
}
|
||||
@@ -564,6 +569,7 @@ namespace v2rayN.Handler
|
||||
publicKey = node.publicKey,
|
||||
shortId = node.shortId,
|
||||
spiderX = node.spiderX,
|
||||
show = false,
|
||||
};
|
||||
|
||||
streamSettings.realitySettings = realitySettings;
|
||||
@@ -629,6 +635,25 @@ namespace v2rayN.Handler
|
||||
}
|
||||
streamSettings.httpupgradeSettings = httpupgradeSettings;
|
||||
|
||||
break;
|
||||
//splithttp
|
||||
case nameof(ETransport.splithttp):
|
||||
SplithttpSettings4Ray splithttpSettings = new()
|
||||
{
|
||||
maxUploadSize = 1000000,
|
||||
maxConcurrentUploads = 10
|
||||
};
|
||||
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
{
|
||||
splithttpSettings.path = node.path;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(host))
|
||||
{
|
||||
splithttpSettings.host = host;
|
||||
}
|
||||
streamSettings.splithttpSettings = splithttpSettings;
|
||||
|
||||
break;
|
||||
//h2
|
||||
case nameof(ETransport.h2):
|
||||
@@ -673,7 +698,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
authority = Utils.IsNullOrEmpty(host) ? null : host,
|
||||
serviceName = node.path,
|
||||
multiMode = (node.headerType == Global.GrpcMultiMode),
|
||||
multiMode = node.headerType == Global.GrpcMultiMode,
|
||||
idle_timeout = _config.grpcItem.idle_timeout,
|
||||
health_check_timeout = _config.grpcItem.health_check_timeout,
|
||||
permit_without_stream = _config.grpcItem.permit_without_stream,
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.IO;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler.CoreConfig;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -39,6 +41,7 @@ namespace v2rayN.Handler
|
||||
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
||||
{
|
||||
ShowMsg(false, msg);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,22 +57,22 @@ namespace v2rayN.Handler
|
||||
CoreStart(node);
|
||||
|
||||
//In tun mode, do a delay check and restart the core
|
||||
if (_config.tunModeItem.enableTun)
|
||||
{
|
||||
Observable.Range(1, 1)
|
||||
.Delay(TimeSpan.FromSeconds(15))
|
||||
.Subscribe(x =>
|
||||
{
|
||||
{
|
||||
if (_process == null || _process.HasExited)
|
||||
{
|
||||
CoreStart(node);
|
||||
ShowMsg(false, "Tun mode restart the core once");
|
||||
Logging.SaveLog("Tun mode restart the core once");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
//if (_config.tunModeItem.enableTun)
|
||||
//{
|
||||
// Observable.Range(1, 1)
|
||||
// .Delay(TimeSpan.FromSeconds(15))
|
||||
// .Subscribe(x =>
|
||||
// {
|
||||
// {
|
||||
// if (_process == null || _process.HasExited)
|
||||
// {
|
||||
// CoreStart(node);
|
||||
// ShowMsg(false, "Tun mode restart the core once");
|
||||
// Logging.SaveLog("Tun mode restart the core once");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,15 +186,16 @@ namespace v2rayN.Handler
|
||||
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||
|
||||
ECoreType coreType;
|
||||
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
||||
{
|
||||
coreType = ECoreType.sing_box;
|
||||
}
|
||||
else
|
||||
{
|
||||
coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||
}
|
||||
//ECoreType coreType;
|
||||
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
||||
//{
|
||||
// coreType = ECoreType.sing_box;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||
//}
|
||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||
_config.runningCoreType = coreType;
|
||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
||||
|
||||
@@ -203,13 +207,25 @@ namespace v2rayN.Handler
|
||||
}
|
||||
_process = proc;
|
||||
|
||||
//start a socks service
|
||||
//start a pre service
|
||||
if (_process != null && !_process.HasExited)
|
||||
{
|
||||
if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
||||
ProfileItem? itemSocks = null;
|
||||
var preCoreType = ECoreType.sing_box;
|
||||
if (node.configType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)
|
||||
{
|
||||
var preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
var itemSocks = new ProfileItem()
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
coreType = preCoreType,
|
||||
configType = EConfigType.Socks,
|
||||
address = Global.Loopback,
|
||||
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||
};
|
||||
}
|
||||
else if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
||||
{
|
||||
preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
coreType = preCoreType,
|
||||
configType = EConfigType.Socks,
|
||||
@@ -217,6 +233,9 @@ namespace v2rayN.Handler
|
||||
port = node.preSocksPort
|
||||
};
|
||||
_config.runningCoreType = preCoreType;
|
||||
}
|
||||
if (itemSocks != null)
|
||||
{
|
||||
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Sockets;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
|
||||
203
v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs
Normal file
203
v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class BaseFmt
|
||||
{
|
||||
protected static string GetIpv6(string address)
|
||||
{
|
||||
if (Utils.IsIpv6(address))
|
||||
{
|
||||
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
|
||||
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
||||
}
|
||||
return address; // 如果不是IPv6地址,直接返回原地址
|
||||
}
|
||||
|
||||
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(item.flow))
|
||||
{
|
||||
dicQuery.Add("flow", item.flow);
|
||||
}
|
||||
|
||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
||||
{
|
||||
dicQuery.Add("security", item.streamSecurity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (securityDef != null)
|
||||
{
|
||||
dicQuery.Add("security", securityDef);
|
||||
}
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
||||
{
|
||||
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||
{
|
||||
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||
{
|
||||
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.spiderX))
|
||||
{
|
||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||
}
|
||||
|
||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||
|
||||
switch (item.network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.http):
|
||||
case nameof(ETransport.h2):
|
||||
dicQuery["type"] = nameof(ETransport.http);
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.quic):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
||||
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
||||
break;
|
||||
|
||||
case nameof(ETransport.grpc):
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
||||
{
|
||||
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||
{
|
||||
item.flow = query["flow"] ?? "";
|
||||
item.streamSecurity = query["security"] ?? "";
|
||||
item.sni = query["sni"] ?? "";
|
||||
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
||||
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
||||
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||
|
||||
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||
switch (item.network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
item.headerType = query["headerType"] ?? Global.None;
|
||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
item.headerType = query["headerType"] ?? Global.None;
|
||||
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||
break;
|
||||
|
||||
case nameof(ETransport.http):
|
||||
case nameof(ETransport.h2):
|
||||
item.network = nameof(ETransport.h2);
|
||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||
break;
|
||||
|
||||
case nameof(ETransport.quic):
|
||||
item.headerType = query["headerType"] ?? Global.None;
|
||||
item.requestHost = query["quicSecurity"] ?? Global.None;
|
||||
item.path = Utils.UrlDecode(query["key"] ?? "");
|
||||
break;
|
||||
|
||||
case nameof(ETransport.grpc):
|
||||
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
|
||||
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
||||
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected static bool Contains(string str, params string[] s)
|
||||
{
|
||||
foreach (var item in s)
|
||||
{
|
||||
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static string WriteAllText(string strData, string ext = "json")
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.{ext}");
|
||||
File.WriteAllText(fileName, strData);
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs
Normal file
26
v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class ClashFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||
{
|
||||
if (Contains(strData, "port", "socks-port", "proxies"))
|
||||
{
|
||||
var fileName = WriteAllText(strData, "yaml");
|
||||
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.mihomo,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "clash_custom"
|
||||
};
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs
Normal file
94
v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class FmtHandler
|
||||
{
|
||||
public static string? GetShareUri(ProfileItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = item.configType switch
|
||||
{
|
||||
EConfigType.VMess => VmessFmt.ToUri(item),
|
||||
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
||||
EConfigType.Socks => SocksFmt.ToUri(item),
|
||||
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
||||
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
||||
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||
EConfigType.Tuic => TuicFmt.ToUri(item),
|
||||
EConfigType.Wireguard => WireguardFmt.ToUri(item),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
return url;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static ProfileItem? ResolveConfig(string config, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
try
|
||||
{
|
||||
string str = config.TrimEx();
|
||||
if (Utils.IsNullOrEmpty(str))
|
||||
{
|
||||
msg = ResUI.FailedReadConfiguration;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
||||
{
|
||||
return VmessFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
|
||||
{
|
||||
return ShadowsocksFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
||||
{
|
||||
return SocksFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
|
||||
{
|
||||
return TrojanFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
|
||||
{
|
||||
return VLESSFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
|
||||
{
|
||||
return Hysteria2Fmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
||||
{
|
||||
return TuicFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
|
||||
{
|
||||
return WireguardFmt.Resolve(str, out msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = ResUI.NonvmessOrssProtocol;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
msg = ResUI.Incorrectconfiguration;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs
Normal file
104
v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class Hysteria2Fmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Hysteria2
|
||||
};
|
||||
|
||||
Uri url = new(str);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
item.id = Utils.UrlDecode(url.UserInfo);
|
||||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
ResolveStdTransport(query, ref item);
|
||||
item.path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("obfs", "salamander");
|
||||
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
|
||||
}
|
||||
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
||||
|
||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||
|
||||
url = string.Format("{0}@{1}:{2}",
|
||||
item.id,
|
||||
GetIpv6(item.address),
|
||||
item.port);
|
||||
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}";
|
||||
return url;
|
||||
}
|
||||
|
||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||
{
|
||||
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
|
||||
{
|
||||
var fileName = WriteAllText(strData);
|
||||
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.hysteria,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "hysteria_custom"
|
||||
};
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
|
||||
{
|
||||
if (Contains(strData, "server", "auth", "up", "down", "listen"))
|
||||
{
|
||||
var fileName = WriteAllText(strData);
|
||||
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.hysteria2,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "hysteria2_custom"
|
||||
};
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs
Normal file
26
v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class NaiveproxyFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||
{
|
||||
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
|
||||
{
|
||||
var fileName = WriteAllText(strData);
|
||||
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.naiveproxy,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "naiveproxy_custom"
|
||||
};
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
183
v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs
Normal file
183
v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class ShadowsocksFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
ProfileItem? item;
|
||||
|
||||
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (item.address.Length == 0 || item.port == 0 || item.security.Length == 0 || item.id.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
item.configType = EConfigType.Shadowsocks;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||
// item.security,
|
||||
// item.id,
|
||||
// item.address,
|
||||
// item.port);
|
||||
//url = Utile.Base64Encode(url);
|
||||
//new Sip002
|
||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
||||
return url;
|
||||
}
|
||||
|
||||
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
private static ProfileItem? ResolveSSLegacy(string result)
|
||||
{
|
||||
var match = UrlFinder.Match(result);
|
||||
if (!match.Success)
|
||||
return null;
|
||||
|
||||
ProfileItem item = new();
|
||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||
var tag = match.Groups["tag"].Value;
|
||||
if (!Utils.IsNullOrEmpty(tag))
|
||||
{
|
||||
item.remarks = Utils.UrlDecode(tag);
|
||||
}
|
||||
Match details;
|
||||
try
|
||||
{
|
||||
details = DetailsParser.Match(Utils.Base64Decode(base64));
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!details.Success)
|
||||
return null;
|
||||
item.security = details.Groups["method"].Value;
|
||||
item.id = details.Groups["password"].Value;
|
||||
item.address = details.Groups["hostname"].Value;
|
||||
item.port = Utils.ToInt(details.Groups["port"].Value);
|
||||
return item;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveSip002(string result)
|
||||
{
|
||||
Uri parsedUrl;
|
||||
try
|
||||
{
|
||||
parsedUrl = new Uri(result);
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ProfileItem item = new()
|
||||
{
|
||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||
address = parsedUrl.IdnHost,
|
||||
port = parsedUrl.Port,
|
||||
};
|
||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
||||
//2022-blake3
|
||||
if (rawUserInfo.Contains(':'))
|
||||
{
|
||||
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.security = userInfoParts[0];
|
||||
item.id = Utils.UrlDecode(userInfoParts[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// parse base64 UserInfo
|
||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.security = userInfoParts[0];
|
||||
item.id = userInfoParts[1];
|
||||
}
|
||||
|
||||
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||
if (queryParameters["plugin"] != null)
|
||||
{
|
||||
//obfs-host exists
|
||||
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
||||
{
|
||||
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||
item.network = Global.DefaultNetwork;
|
||||
item.headerType = Global.TcpHeaderHttp;
|
||||
item.requestHost = obfsHost ?? "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static List<ProfileItem>? ResolveSip008(string result)
|
||||
{
|
||||
//SsSIP008
|
||||
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
|
||||
if (lstSsServer?.Count <= 0)
|
||||
{
|
||||
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
|
||||
if (ssSIP008?.servers?.Count > 0)
|
||||
{
|
||||
lstSsServer = ssSIP008.servers;
|
||||
}
|
||||
}
|
||||
|
||||
if (lstSsServer?.Count > 0)
|
||||
{
|
||||
List<ProfileItem> lst = [];
|
||||
foreach (var it in lstSsServer)
|
||||
{
|
||||
var ssItem = new ProfileItem()
|
||||
{
|
||||
remarks = it.remarks,
|
||||
security = it.method,
|
||||
id = it.password,
|
||||
address = it.server,
|
||||
port = Utils.ToInt(it.server_port)
|
||||
};
|
||||
lst.Add(ssItem);
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs
Normal file
58
v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class SingboxFmt : BaseFmt
|
||||
{
|
||||
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||
{
|
||||
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||
if (configObjects != null && configObjects.Length > 0)
|
||||
{
|
||||
List<ProfileItem> lstResult = [];
|
||||
foreach (var configObject in configObjects)
|
||||
{
|
||||
var objectString = JsonUtils.Serialize(configObject);
|
||||
var singboxCon = JsonUtils.Deserialize<SingboxConfig>(objectString);
|
||||
if (singboxCon?.inbounds?.Count > 0
|
||||
&& singboxCon.outbounds?.Count > 0
|
||||
&& singboxCon.route != null)
|
||||
{
|
||||
var fileName = WriteAllText(objectString);
|
||||
|
||||
var profileIt = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.sing_box,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "singbox_custom",
|
||||
};
|
||||
lstResult.Add(profileIt);
|
||||
}
|
||||
}
|
||||
return lstResult;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||
{
|
||||
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(strData);
|
||||
if (singboxConfig?.inbounds?.Count > 0
|
||||
&& singboxConfig.outbounds?.Count > 0
|
||||
&& singboxConfig.route != null)
|
||||
{
|
||||
var fileName = WriteAllText(strData);
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.sing_box,
|
||||
address = fileName,
|
||||
remarks = subRemarks ?? "singbox_custom"
|
||||
};
|
||||
|
||||
return profileItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
131
v2rayN/v2rayN/Handler/Fmt/SocksFmt.cs
Normal file
131
v2rayN/v2rayN/Handler/Fmt/SocksFmt.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class SocksFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
ProfileItem? item;
|
||||
|
||||
item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (item.address.Length == 0 || item.port == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
item.configType = EConfigType.Socks;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||
// item.security,
|
||||
// item.id,
|
||||
// item.address,
|
||||
// item.port);
|
||||
//url = Utile.Base64Encode(url);
|
||||
//new
|
||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
||||
return url;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveSocks(string result)
|
||||
{
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Socks
|
||||
};
|
||||
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
||||
//remark
|
||||
int indexRemark = result.IndexOf("#");
|
||||
if (indexRemark > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
item.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
||||
}
|
||||
catch { }
|
||||
result = result[..indexRemark];
|
||||
}
|
||||
//part decode
|
||||
int indexS = result.IndexOf("@");
|
||||
if (indexS > 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Utils.Base64Decode(result);
|
||||
}
|
||||
|
||||
string[] arr1 = result.Split('@');
|
||||
if (arr1.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] arr21 = arr1[0].Split(':');
|
||||
//string[] arr22 = arr1[1].Split(':');
|
||||
int indexPort = arr1[1].LastIndexOf(":");
|
||||
if (arr21.Length != 2 || indexPort < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.address = arr1[1][..indexPort];
|
||||
item.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||
item.security = arr21[0];
|
||||
item.id = arr21[1];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveSocksNew(string result)
|
||||
{
|
||||
Uri parsedUrl;
|
||||
try
|
||||
{
|
||||
parsedUrl = new Uri(result);
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ProfileItem item = new()
|
||||
{
|
||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||
address = parsedUrl.IdnHost,
|
||||
port = parsedUrl.Port,
|
||||
};
|
||||
|
||||
// parse base64 UserInfo
|
||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
|
||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length == 2)
|
||||
{
|
||||
item.security = userInfoParts[0];
|
||||
item.id = userInfoParts[1];
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
v2rayN/v2rayN/Handler/Fmt/TrojanFmt.cs
Normal file
53
v2rayN/v2rayN/Handler/Fmt/TrojanFmt.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class TrojanFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Trojan
|
||||
};
|
||||
|
||||
Uri url = new(str);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
item.id = Utils.UrlDecode(url.UserInfo);
|
||||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
ResolveStdTransport(query, ref item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
GetStdTransport(item, null, ref dicQuery);
|
||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||
|
||||
url = string.Format("{0}@{1}:{2}",
|
||||
item.id,
|
||||
GetIpv6(item.address),
|
||||
item.port);
|
||||
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
v2rayN/v2rayN/Handler/Fmt/TuicFmt.cs
Normal file
68
v2rayN/v2rayN/Handler/Fmt/TuicFmt.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class TuicFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Tuic
|
||||
};
|
||||
|
||||
Uri url = new(str);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length == 2)
|
||||
{
|
||||
item.id = userInfoParts[0];
|
||||
item.security = userInfoParts[1];
|
||||
}
|
||||
|
||||
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;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
dicQuery.Add("congestion_control", item.headerType);
|
||||
|
||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||
|
||||
url = string.Format("{0}@{1}:{2}",
|
||||
$"{item.id}:{item.security}",
|
||||
GetIpv6(item.address),
|
||||
item.port);
|
||||
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs
Normal file
59
v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class V2rayFmt : BaseFmt
|
||||
{
|
||||
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||
{
|
||||
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||
if (configObjects != null && configObjects.Length > 0)
|
||||
{
|
||||
List<ProfileItem> lstResult = [];
|
||||
foreach (var configObject in configObjects)
|
||||
{
|
||||
var objectString = JsonUtils.Serialize(configObject);
|
||||
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
|
||||
if (v2rayCon?.inbounds?.Count > 0
|
||||
&& v2rayCon.outbounds?.Count > 0
|
||||
&& v2rayCon.routing != null)
|
||||
{
|
||||
var fileName = WriteAllText(objectString);
|
||||
|
||||
var profileIt = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.Xray,
|
||||
address = fileName,
|
||||
remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
|
||||
};
|
||||
lstResult.Add(profileIt);
|
||||
}
|
||||
}
|
||||
return lstResult;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||
{
|
||||
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(strData);
|
||||
if (v2rayConfig?.inbounds?.Count > 0
|
||||
&& v2rayConfig.outbounds?.Count > 0
|
||||
&& v2rayConfig.routing != null)
|
||||
{
|
||||
var fileName = WriteAllText(strData);
|
||||
|
||||
var profileItem = new ProfileItem
|
||||
{
|
||||
coreType = ECoreType.Xray,
|
||||
address = fileName,
|
||||
remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
|
||||
};
|
||||
|
||||
return profileItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
v2rayN/v2rayN/Handler/Fmt/VLESSFmt.cs
Normal file
64
v2rayN/v2rayN/Handler/Fmt/VLESSFmt.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class VLESSFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.VLESS,
|
||||
security = Global.None
|
||||
};
|
||||
|
||||
Uri url = new(str);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
item.id = Utils.UrlDecode(url.UserInfo);
|
||||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
item.security = query["encryption"] ?? Global.None;
|
||||
item.streamSecurity = query["security"] ?? "";
|
||||
ResolveStdTransport(query, ref item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.security))
|
||||
{
|
||||
dicQuery.Add("encryption", item.security);
|
||||
}
|
||||
else
|
||||
{
|
||||
dicQuery.Add("encryption", Global.None);
|
||||
}
|
||||
GetStdTransport(item, Global.None, ref dicQuery);
|
||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||
|
||||
url = string.Format("{0}@{1}:{2}",
|
||||
item.id,
|
||||
GetIpv6(item.address),
|
||||
item.port);
|
||||
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
229
v2rayN/v2rayN/Handler/Fmt/VmessFmt.cs
Normal file
229
v2rayN/v2rayN/Handler/Fmt/VmessFmt.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class VmessFmt : BaseFmt
|
||||
{
|
||||
private static readonly Regex StdVmessUserInfo = new(
|
||||
@"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled);
|
||||
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
ProfileItem? item;
|
||||
int indexSplit = str.IndexOf("?");
|
||||
if (indexSplit > 0)
|
||||
{
|
||||
item = ResolveStdVmess(str) ?? ResolveVmess4Kitsunebi(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = ResolveVmess(str, out msg);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
VmessQRCode vmessQRCode = new()
|
||||
{
|
||||
v = item.configVersion,
|
||||
ps = item.remarks.TrimEx(),
|
||||
add = item.address,
|
||||
port = item.port,
|
||||
id = item.id,
|
||||
aid = item.alterId,
|
||||
scy = item.security,
|
||||
net = item.network,
|
||||
type = item.headerType,
|
||||
host = item.requestHost,
|
||||
path = item.path,
|
||||
tls = item.streamSecurity,
|
||||
sni = item.sni,
|
||||
alpn = item.alpn,
|
||||
fp = item.fingerprint
|
||||
};
|
||||
|
||||
url = JsonUtils.Serialize(vmessQRCode);
|
||||
url = Utils.Base64Encode(url);
|
||||
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveVmess(string result, out string msg)
|
||||
{
|
||||
msg = string.Empty;
|
||||
var item = new ProfileItem
|
||||
{
|
||||
configType = EConfigType.VMess
|
||||
};
|
||||
|
||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||
result = Utils.Base64Decode(result);
|
||||
|
||||
//转成Json
|
||||
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||
if (vmessQRCode == null)
|
||||
{
|
||||
msg = ResUI.FailedConversionConfiguration;
|
||||
return null;
|
||||
}
|
||||
|
||||
item.network = Global.DefaultNetwork;
|
||||
item.headerType = Global.None;
|
||||
|
||||
item.configVersion = Utils.ToInt(vmessQRCode.v);
|
||||
item.remarks = Utils.ToString(vmessQRCode.ps);
|
||||
item.address = Utils.ToString(vmessQRCode.add);
|
||||
item.port = Utils.ToInt(vmessQRCode.port);
|
||||
item.id = Utils.ToString(vmessQRCode.id);
|
||||
item.alterId = Utils.ToInt(vmessQRCode.aid);
|
||||
item.security = Utils.ToString(vmessQRCode.scy);
|
||||
|
||||
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
||||
{
|
||||
item.network = vmessQRCode.net;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
||||
{
|
||||
item.headerType = vmessQRCode.type;
|
||||
}
|
||||
|
||||
item.requestHost = Utils.ToString(vmessQRCode.host);
|
||||
item.path = Utils.ToString(vmessQRCode.path);
|
||||
item.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
||||
item.sni = Utils.ToString(vmessQRCode.sni);
|
||||
item.alpn = Utils.ToString(vmessQRCode.alpn);
|
||||
item.fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveStdVmess(string result)
|
||||
{
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.VMess,
|
||||
security = "auto"
|
||||
};
|
||||
|
||||
Uri u = new(result);
|
||||
|
||||
item.address = u.IdnHost;
|
||||
item.port = u.Port;
|
||||
item.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
var query = Utils.ParseQueryString(u.Query);
|
||||
|
||||
var m = StdVmessUserInfo.Match(u.UserInfo);
|
||||
if (!m.Success) return null;
|
||||
|
||||
item.id = m.Groups["id"].Value;
|
||||
|
||||
if (m.Groups["streamSecurity"].Success)
|
||||
{
|
||||
item.streamSecurity = m.Groups["streamSecurity"].Value;
|
||||
}
|
||||
switch (item.streamSecurity)
|
||||
{
|
||||
case Global.StreamSecurity:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
|
||||
item.network = m.Groups["network"].Value;
|
||||
switch (item.network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
string t1 = query["type"] ?? Global.None;
|
||||
item.headerType = t1;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
item.headerType = query["type"] ?? Global.None;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
string p1 = query["path"] ?? "/";
|
||||
string h1 = query["host"] ?? "";
|
||||
item.requestHost = Utils.UrlDecode(h1);
|
||||
item.path = p1;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.http):
|
||||
case nameof(ETransport.h2):
|
||||
item.network = nameof(ETransport.h2);
|
||||
string p2 = query["path"] ?? "/";
|
||||
string h2 = query["host"] ?? "";
|
||||
item.requestHost = Utils.UrlDecode(h2);
|
||||
item.path = p2;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.quic):
|
||||
string s = query["security"] ?? Global.None;
|
||||
string k = query["key"] ?? "";
|
||||
string t3 = query["type"] ?? Global.None;
|
||||
item.headerType = t3;
|
||||
item.requestHost = Utils.UrlDecode(s);
|
||||
item.path = k;
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
|
||||
{
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.VMess
|
||||
};
|
||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||
int indexSplit = result.IndexOf("?");
|
||||
if (indexSplit > 0)
|
||||
{
|
||||
result = result[..indexSplit];
|
||||
}
|
||||
result = Utils.Base64Decode(result);
|
||||
|
||||
string[] arr1 = result.Split('@');
|
||||
if (arr1.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] arr21 = arr1[0].Split(':');
|
||||
string[] arr22 = arr1[1].Split(':');
|
||||
if (arr21.Length != 2 || arr22.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
item.address = arr22[0];
|
||||
item.port = Utils.ToInt(arr22[1]);
|
||||
item.security = arr21[0];
|
||||
item.id = arr21[1];
|
||||
|
||||
item.network = Global.DefaultNetwork;
|
||||
item.headerType = Global.None;
|
||||
item.remarks = "Alien";
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
v2rayN/v2rayN/Handler/Fmt/WireguardFmt.cs
Normal file
73
v2rayN/v2rayN/Handler/Fmt/WireguardFmt.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Handler.Fmt
|
||||
{
|
||||
internal class WireguardFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Wireguard
|
||||
};
|
||||
|
||||
Uri url = new(str);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||
item.id = Utils.UrlDecode(url.UserInfo);
|
||||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
|
||||
item.publicKey = Utils.UrlDecode(query["publickey"] ?? "");
|
||||
item.path = Utils.UrlDecode(query["reserved"] ?? "");
|
||||
item.requestHost = Utils.UrlDecode(query["address"] ?? "");
|
||||
item.shortId = Utils.UrlDecode(query["mtu"] ?? "");
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||
{
|
||||
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||
{
|
||||
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
|
||||
}
|
||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||
|
||||
url = string.Format("{0}@{1}:{2}",
|
||||
Utils.UrlEncode(item.id),
|
||||
GetIpv6(item.address),
|
||||
item.port);
|
||||
url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
@@ -12,20 +13,26 @@ namespace v2rayN.Handler
|
||||
public static LazyConfig Instance => _instance.Value;
|
||||
|
||||
private int? _statePort;
|
||||
private int? _statePort2;
|
||||
|
||||
public int StatePort
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_statePort is null)
|
||||
{
|
||||
_statePort = Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||
}
|
||||
|
||||
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||
return _statePort.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public int StatePort2
|
||||
{
|
||||
get
|
||||
{
|
||||
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||
return _statePort2.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private Job _processJob = new();
|
||||
|
||||
public LazyConfig()
|
||||
|
||||
@@ -3,6 +3,8 @@ using Splat;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Media.Imaging;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler.CoreConfig;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
@@ -27,7 +28,7 @@ namespace v2rayN.Handler
|
||||
|
||||
try
|
||||
{
|
||||
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort}/traffic";
|
||||
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort2}/traffic";
|
||||
|
||||
if (webSocket == null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using ProtosLib.Statistics;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
@@ -86,6 +87,8 @@ namespace v2rayN.Handler
|
||||
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
||||
{
|
||||
server = new();
|
||||
long aggregateProxyUp = 0;
|
||||
long aggregateProxyDown = 0;
|
||||
try
|
||||
{
|
||||
foreach (Stat stat in source)
|
||||
@@ -100,15 +103,15 @@ namespace v2rayN.Handler
|
||||
name = nStr[1];
|
||||
type = nStr[3];
|
||||
|
||||
if (name == Global.ProxyTag)
|
||||
if (name.StartsWith(Global.ProxyTag))
|
||||
{
|
||||
if (type == "uplink")
|
||||
{
|
||||
server.proxyUp = value;
|
||||
aggregateProxyUp += value;
|
||||
}
|
||||
else if (type == "downlink")
|
||||
{
|
||||
server.proxyDown = value;
|
||||
aggregateProxyDown += value;
|
||||
}
|
||||
}
|
||||
else if (name == Global.DirectTag)
|
||||
@@ -123,6 +126,8 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
}
|
||||
server.proxyUp = aggregateProxyUp;
|
||||
server.proxyDown = aggregateProxyDown;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using PacLib;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -299,9 +300,6 @@ namespace v2rayN.Handler
|
||||
{
|
||||
await UpdateGeoFile("geosite", _config, update);
|
||||
await UpdateGeoFile("geoip", _config, update);
|
||||
|
||||
//await UpdateGeoFile4Singbox("geosite", _config, false, update);
|
||||
//await UpdateGeoFile4Singbox("geoip", _config, true, update);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -327,7 +325,7 @@ namespace v2rayN.Handler
|
||||
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
||||
if (!Utils.IsNullOrEmpty(result))
|
||||
{
|
||||
responseHandler(type, result, preRelease);
|
||||
ResponseHandler(type, result, preRelease);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -345,7 +343,7 @@ namespace v2rayN.Handler
|
||||
/// <summary>
|
||||
/// 获取V2RayCore版本
|
||||
/// </summary>
|
||||
private SemanticVersion getCoreVersion(ECoreType type)
|
||||
private SemanticVersion GetCoreVersion(ECoreType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -410,7 +408,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
|
||||
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
||||
private void ResponseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -431,7 +429,7 @@ namespace v2rayN.Handler
|
||||
case ECoreType.Xray:
|
||||
case ECoreType.v2fly_v5:
|
||||
{
|
||||
curVersion = getCoreVersion(type);
|
||||
curVersion = GetCoreVersion(type);
|
||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||
string osBit = "64";
|
||||
switch (RuntimeInformation.ProcessArchitecture)
|
||||
@@ -456,7 +454,7 @@ namespace v2rayN.Handler
|
||||
case ECoreType.clash_meta:
|
||||
case ECoreType.mihomo:
|
||||
{
|
||||
curVersion = getCoreVersion(type);
|
||||
curVersion = GetCoreVersion(type);
|
||||
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
||||
switch (RuntimeInformation.ProcessArchitecture)
|
||||
{
|
||||
@@ -477,7 +475,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
case ECoreType.sing_box:
|
||||
{
|
||||
curVersion = getCoreVersion(type);
|
||||
curVersion = GetCoreVersion(type);
|
||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||
switch (RuntimeInformation.ProcessArchitecture)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace v2rayN.Models
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 本软件配置文件实体类
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Windows.Input;
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
@@ -186,7 +187,7 @@ namespace v2rayN.Models
|
||||
public string domainStrategy4Singbox { get; set; }
|
||||
public string domainMatcher { get; set; }
|
||||
public string routingIndexId { get; set; }
|
||||
public bool enableRoutingAdvanced { get; set; }
|
||||
public bool enableRoutingAdvanced { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -1,440 +0,0 @@
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class ConfigOld
|
||||
{
|
||||
#region property
|
||||
|
||||
/// <summary>
|
||||
/// 允许日志
|
||||
/// </summary>
|
||||
public bool logEnabled
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志等级
|
||||
/// </summary>
|
||||
public string loglevel
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string indexId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 允许Mux多路复用
|
||||
/// </summary>
|
||||
public bool muxEnabled
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ESysProxyType sysProxyType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用实时网速和流量统计
|
||||
/// </summary>
|
||||
public bool enableStatistics
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去重时优先保留较旧(顶部)节点
|
||||
/// </summary>
|
||||
public bool keepOlderDedupl
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 视图刷新率
|
||||
/// </summary>
|
||||
public int statisticsFreshRate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义远程DNS
|
||||
/// </summary>
|
||||
public string remoteDNS
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outbound Freedom domainStrategy
|
||||
/// </summary>
|
||||
public string domainStrategy4Freedom
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许不安全连接
|
||||
/// </summary>
|
||||
public bool defAllowInsecure
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 域名解析策略
|
||||
/// </summary>
|
||||
public string domainStrategy
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string domainMatcher
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int routingIndex
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool enableRoutingAdvanced
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool ignoreGeoUpdateCore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// systemProxyExceptions
|
||||
/// </summary>
|
||||
public string systemProxyExceptions
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string systemProxyAdvancedProtocol { get; set; }
|
||||
|
||||
public int autoUpdateInterval { get; set; } = 0;
|
||||
|
||||
public int autoUpdateSubInterval { get; set; } = 0;
|
||||
|
||||
public bool checkPreReleaseUpdate { get; set; } = false;
|
||||
|
||||
public bool enableSecurityProtocolTls13
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int trayMenuServersLimit { get; set; }
|
||||
|
||||
#endregion property
|
||||
|
||||
#region other entities
|
||||
|
||||
/// <summary>
|
||||
/// 本地监听
|
||||
/// </summary>
|
||||
public List<InItem> inbound
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// vmess服务器信息
|
||||
/// </summary>
|
||||
public List<VmessItem> vmess
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// KcpItem
|
||||
/// </summary>
|
||||
public KcpItem kcpItem
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 订阅
|
||||
/// </summary>
|
||||
public List<SubItem> subItem
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI
|
||||
/// </summary>
|
||||
public UIItem uiItem
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<RoutingItemOld> routings
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public ConstItem constItem
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<KeyEventItem> globalHotkeys
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<CoreTypeItem> coreTypeItem
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
#endregion other entities
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class VmessItem
|
||||
{
|
||||
public VmessItem()
|
||||
{
|
||||
indexId = string.Empty;
|
||||
configType = EConfigType.VMess;
|
||||
configVersion = 2;
|
||||
sort = 0;
|
||||
address = string.Empty;
|
||||
port = 0;
|
||||
id = string.Empty;
|
||||
alterId = 0;
|
||||
security = string.Empty;
|
||||
network = string.Empty;
|
||||
remarks = string.Empty;
|
||||
headerType = string.Empty;
|
||||
requestHost = string.Empty;
|
||||
path = string.Empty;
|
||||
streamSecurity = string.Empty;
|
||||
allowInsecure = string.Empty;
|
||||
testResult = string.Empty;
|
||||
subid = string.Empty;
|
||||
flow = string.Empty;
|
||||
groupId = string.Empty;
|
||||
}
|
||||
|
||||
public string indexId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// config type(1=normal,2=custom)
|
||||
/// </summary>
|
||||
public EConfigType configType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 版本(现在=2)
|
||||
/// </summary>
|
||||
public int configVersion
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int sort
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程服务器地址
|
||||
/// </summary>
|
||||
public string address
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程服务器端口
|
||||
/// </summary>
|
||||
public int port
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程服务器ID
|
||||
/// </summary>
|
||||
public string id
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程服务器额外ID
|
||||
/// </summary>
|
||||
public int alterId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地安全策略
|
||||
/// </summary>
|
||||
public string security
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// tcp,kcp,ws,h2,quic
|
||||
/// </summary>
|
||||
public string network
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string remarks
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string headerType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 伪装的域名
|
||||
/// </summary>
|
||||
public string requestHost
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ws h2 path
|
||||
/// </summary>
|
||||
public string path
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传输层安全
|
||||
/// </summary>
|
||||
public string streamSecurity
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许不安全连接(用于客户端)
|
||||
/// </summary>
|
||||
public string allowInsecure
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string testResult
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SubItem id
|
||||
/// </summary>
|
||||
public string subid
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// VLESS flow
|
||||
/// </summary>
|
||||
public string flow
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// tls sni
|
||||
/// </summary>
|
||||
public string sni
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string groupId
|
||||
{
|
||||
get; set;
|
||||
} = string.Empty;
|
||||
|
||||
public ECoreType? coreType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int preSocksPort
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string fingerprint { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RoutingItemOld
|
||||
{
|
||||
public string remarks
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string url
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<RulesItem> rules
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool enabled { get; set; } = true;
|
||||
|
||||
public bool locked
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string customIcon
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace v2rayN.Models
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class CoreInfo
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SQLite;
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SQLite;
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
|
||||
@@ -4,21 +4,22 @@
|
||||
public class RulesItem
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string type { get; set; }
|
||||
public string? type { get; set; }
|
||||
|
||||
public string port { get; set; }
|
||||
public string? port { get; set; }
|
||||
public string? network { get; set; }
|
||||
|
||||
public List<string> inboundTag { get; set; }
|
||||
public List<string>? inboundTag { get; set; }
|
||||
|
||||
public string outboundTag { get; set; }
|
||||
public string? outboundTag { get; set; }
|
||||
|
||||
public List<string> ip { get; set; }
|
||||
public List<string>? ip { get; set; }
|
||||
|
||||
public List<string> domain { get; set; }
|
||||
public List<string>? domain { get; set; }
|
||||
|
||||
public List<string> protocol { get; set; }
|
||||
public List<string>? protocol { get; set; }
|
||||
|
||||
public List<string> process { get; set; }
|
||||
public List<string>? process { get; set; }
|
||||
|
||||
public bool enabled { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace v2rayN.Models
|
||||
using v2rayN.Enums;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
[Serializable]
|
||||
internal class ServerTestItem
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
public bool? disable_expire { get; set; }
|
||||
public bool? independent_cache { get; set; }
|
||||
public bool? reverse_mapping { get; set; }
|
||||
public string? client_subnet { get; set; }
|
||||
public Fakeip4Sbox? fakeip { get; set; }
|
||||
}
|
||||
|
||||
@@ -44,12 +45,13 @@
|
||||
public string? outbound { get; set; }
|
||||
public string? server { get; set; }
|
||||
public bool? disable_cache { get; set; }
|
||||
public List<string>? inbound { get; set; }
|
||||
public List<string>? protocol { get; set; }
|
||||
public string? type { get; set; }
|
||||
public string? mode { get; set; }
|
||||
public string? network { get; set; }
|
||||
public bool? ip_is_private { get; set; }
|
||||
public string? client_subnet { get; set; }
|
||||
public List<string>? inbound { get; set; }
|
||||
public List<string>? protocol { get; set; }
|
||||
public List<string>? network { get; set; }
|
||||
public List<int>? port { get; set; }
|
||||
public List<string>? port_range { get; set; }
|
||||
public List<string>? geosite { get; set; }
|
||||
@@ -62,6 +64,7 @@
|
||||
public List<string>? source_ip_cidr { get; set; }
|
||||
public List<string>? process_name { get; set; }
|
||||
public List<string>? rule_set { get; set; }
|
||||
public List<Rule4Sbox>? rules { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -184,11 +187,13 @@
|
||||
|
||||
public class Server4Sbox
|
||||
{
|
||||
public string tag { get; set; }
|
||||
public string address { get; set; }
|
||||
public string address_resolver { get; set; }
|
||||
public string strategy { get; set; }
|
||||
public string? tag { get; set; }
|
||||
public string? address { get; set; }
|
||||
public string? address_resolver { get; set; }
|
||||
public string? address_strategy { get; set; }
|
||||
public string? strategy { get; set; }
|
||||
public string? detour { get; set; }
|
||||
public string? client_subnet { get; set; }
|
||||
}
|
||||
|
||||
public class Experimental4Sbox
|
||||
@@ -241,6 +246,6 @@
|
||||
public string? path { get; set; }
|
||||
public string? url { get; set; }
|
||||
public string? download_detour { get; set; }
|
||||
public string? update_interval { get; set; }
|
||||
public string? update_interval { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -394,6 +394,7 @@ namespace v2rayN.Models
|
||||
public string? type { get; set; }
|
||||
|
||||
public string? port { get; set; }
|
||||
public string? network { get; set; }
|
||||
|
||||
public List<string>? inboundTag { get; set; }
|
||||
|
||||
@@ -421,47 +422,52 @@ namespace v2rayN.Models
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TlsSettings4Ray tlsSettings { get; set; }
|
||||
public TlsSettings4Ray? tlsSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tcp传输额外设置
|
||||
/// </summary>
|
||||
public TcpSettings4Ray tcpSettings { get; set; }
|
||||
public TcpSettings4Ray? tcpSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Kcp传输额外设置
|
||||
/// </summary>
|
||||
public KcpSettings4Ray kcpSettings { get; set; }
|
||||
public KcpSettings4Ray? kcpSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ws传输额外设置
|
||||
/// </summary>
|
||||
public WsSettings4Ray wsSettings { get; set; }
|
||||
public WsSettings4Ray? wsSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SplithttpSettings4Ray? splithttpSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// h2传输额外设置
|
||||
/// </summary>
|
||||
public HttpSettings4Ray httpSettings { get; set; }
|
||||
public HttpSettings4Ray? httpSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// QUIC
|
||||
/// </summary>
|
||||
public QuicSettings4Ray quicSettings { get; set; }
|
||||
public QuicSettings4Ray? quicSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// VLESS only
|
||||
/// </summary>
|
||||
public TlsSettings4Ray realitySettings { get; set; }
|
||||
public TlsSettings4Ray? realitySettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// grpc
|
||||
/// </summary>
|
||||
public GrpcSettings4Ray grpcSettings { get; set; }
|
||||
public GrpcSettings4Ray? grpcSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sockopt
|
||||
@@ -488,7 +494,7 @@ namespace v2rayN.Models
|
||||
|
||||
public string? fingerprint { get; set; }
|
||||
|
||||
public bool? show { get; set; } = false;
|
||||
public bool? show { get; set; }
|
||||
public string? publicKey { get; set; }
|
||||
public string? shortId { get; set; }
|
||||
public string? spiderX { get; set; }
|
||||
@@ -608,6 +614,17 @@ namespace v2rayN.Models
|
||||
public string? host { get; set; }
|
||||
}
|
||||
|
||||
public class SplithttpSettings4Ray
|
||||
{
|
||||
public string? path { get; set; }
|
||||
|
||||
public string? host { get; set; }
|
||||
|
||||
public int? maxUploadSize { get; set; }
|
||||
|
||||
public int? maxConcurrentUploads { get; set; }
|
||||
}
|
||||
|
||||
public class HttpSettings4Ray
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
4
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
4
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
@@ -3266,7 +3266,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 *ws/httpupgrade path 的本地化字符串。
|
||||
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TransportPathTip1 {
|
||||
get {
|
||||
@@ -3320,7 +3320,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 *ws/httpupgrade host 的本地化字符串。
|
||||
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TransportRequestHostTip2 {
|
||||
get {
|
||||
|
||||
@@ -359,7 +359,7 @@
|
||||
<value>Please fill in the correct custom DNS</value>
|
||||
</data>
|
||||
<data name="TransportPathTip1" xml:space="preserve">
|
||||
<value>*ws/httpupgrade path</value>
|
||||
<value>*ws/httpupgrade/splithttp path</value>
|
||||
</data>
|
||||
<data name="TransportPathTip2" xml:space="preserve">
|
||||
<value>*h2 path</value>
|
||||
@@ -374,7 +374,7 @@
|
||||
<value>*http host Separated by commas (,)</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||
<value>*ws/httpupgrade host</value>
|
||||
<value>*ws/httpupgrade/splithttp host</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||
<value>*h2 host Separated by commas (,)</value>
|
||||
|
||||
@@ -359,7 +359,7 @@
|
||||
<value>请填写正确的自定义DNS</value>
|
||||
</data>
|
||||
<data name="TransportPathTip1" xml:space="preserve">
|
||||
<value>*ws/httpupgrade path</value>
|
||||
<value>*ws/httpupgrade/splithttp path</value>
|
||||
</data>
|
||||
<data name="TransportPathTip2" xml:space="preserve">
|
||||
<value>*h2 path</value>
|
||||
@@ -374,7 +374,7 @@
|
||||
<value>*http host中间逗号(,)分隔</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||
<value>*ws/httpupgrade host</value>
|
||||
<value>*ws/httpupgrade/splithttp host</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||
<value>*h2 host中间逗号(,)分隔</value>
|
||||
|
||||
@@ -358,7 +358,7 @@
|
||||
<value>請填寫正確的自訂DNS</value>
|
||||
</data>
|
||||
<data name="TransportPathTip1" xml:space="preserve">
|
||||
<value>*ws/httpupgrade path</value>
|
||||
<value>*ws/httpupgrade/splithttp path</value>
|
||||
</data>
|
||||
<data name="TransportPathTip2" xml:space="preserve">
|
||||
<value>*h2 path</value>
|
||||
@@ -373,7 +373,7 @@
|
||||
<value>*http host中間逗號(,)分隔</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||
<value>*ws/httpupgrade host</value>
|
||||
<value>*ws/httpupgrade/splithttp host</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||
<value>*h2 host中間逗號(,)分隔</value>
|
||||
|
||||
@@ -16,7 +16,22 @@
|
||||
|
||||
"domain": [
|
||||
"geosite:geolocation-!cn",
|
||||
"geosite:greatfire"
|
||||
"geosite:greatfire"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"1.0.0.1",
|
||||
"1.1.1.1",
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"geoip:facebook",
|
||||
"geoip:fastly",
|
||||
"geoip:google",
|
||||
"geoip:netflix",
|
||||
"geoip:telegram",
|
||||
"geoip:twitter"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
{
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"223.5.5.5/32",
|
||||
"119.29.29.29/32",
|
||||
"180.76.76.76/32",
|
||||
"114.114.114.114/32",
|
||||
"geoip:private",
|
||||
"geoip:cn"
|
||||
]
|
||||
|
||||
@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Reactive;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Reactive;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -14,7 +14,9 @@ using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Handler.Fmt;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
using v2rayN.Views;
|
||||
@@ -1152,7 +1154,7 @@ namespace v2rayN.ViewModels
|
||||
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||
return;
|
||||
}
|
||||
var url = ShareHandler.GetShareUrl(item);
|
||||
var url = FmtHandler.GetShareUri(item);
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
return;
|
||||
@@ -1293,7 +1295,7 @@ namespace v2rayN.ViewModels
|
||||
StringBuilder sb = new();
|
||||
foreach (var it in lstSelecteds)
|
||||
{
|
||||
string url = ShareHandler.GetShareUrl(it);
|
||||
string url = FmtHandler.GetShareUri(it);
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
continue;
|
||||
@@ -1318,7 +1320,7 @@ namespace v2rayN.ViewModels
|
||||
StringBuilder sb = new();
|
||||
foreach (var it in lstSelecteds)
|
||||
{
|
||||
string? url = ShareHandler.GetShareUrl(it);
|
||||
string? url = FmtHandler.GetShareUri(it);
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -3,6 +3,7 @@ using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Reactive;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
@@ -263,7 +264,7 @@ namespace v2rayN.ViewModels
|
||||
var needReboot = (EnableStatistics != _config.guiItem.enableStatistics
|
||||
|| EnableDragDropSort != _config.uiItem.enableDragDropSort
|
||||
|| EnableHWA != _config.guiItem.enableHWA
|
||||
|| CurrentFontFamily != _config.uiItem.currentFontFamily);
|
||||
|| CurrentFontFamily != _config.uiItem.currentFontFamily);
|
||||
|
||||
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
|
||||
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
|
||||
|
||||
@@ -4,6 +4,7 @@ using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Reactive;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
@@ -129,6 +130,7 @@ namespace v2rayN.ViewModels
|
||||
id = item.id,
|
||||
outboundTag = item.outboundTag,
|
||||
port = item.port,
|
||||
network = item.network,
|
||||
protocols = Utils.List2String(item.protocol),
|
||||
inboundTags = Utils.List2String(item.inboundTag),
|
||||
domains = Utils.List2String(item.domain),
|
||||
@@ -289,7 +291,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
private void ImportRulesFromClipboard()
|
||||
{
|
||||
string clipboardData = Utils.GetClipboardData();
|
||||
var clipboardData = Utils.GetClipboardData();
|
||||
if (AddBatchRoutingRules(SelectedRouting, clipboardData) == 0)
|
||||
{
|
||||
RefreshRulesItems();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.ViewModels;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
@@ -332,6 +333,7 @@ namespace v2rayN.Views
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
break;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using v2rayN.Base;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace v2rayN.Views
|
||||
_config.inbound[0].destOverride?.ForEach(it =>
|
||||
{
|
||||
clbdestOverride.SelectedItems.Add(it);
|
||||
});
|
||||
});
|
||||
Global.IEProxyProtocols.ForEach(it =>
|
||||
{
|
||||
cmbsystemProxyAdvancedProtocol.Items.Add(it);
|
||||
|
||||
@@ -125,16 +125,32 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="network" />
|
||||
<ComboBox
|
||||
x:Name="cmbNetwork"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="4"
|
||||
MaxDropDownHeight="1000"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="enabled" />
|
||||
<ToggleButton
|
||||
x:Name="togEnabled"
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace v2rayN.Views
|
||||
{
|
||||
clbInboundTag.Items.Add(it);
|
||||
});
|
||||
Global.RuleNetworks.ForEach(it =>
|
||||
{
|
||||
cmbNetwork.Items.Add(it);
|
||||
});
|
||||
|
||||
if (!rulesItem.id.IsNullOrEmpty())
|
||||
{
|
||||
@@ -56,6 +60,7 @@ namespace v2rayN.Views
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.outboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.network, v => v.cmbNetwork.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Domain, v => v.txtDomain.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.IP, v => v.txtIP.Text).DisposeWith(disposables);
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="110"
|
||||
Binding="{Binding outboundTag}"
|
||||
Header="outboundTag" />
|
||||
<DataGridTextColumn
|
||||
@@ -310,7 +310,7 @@
|
||||
Binding="{Binding port}"
|
||||
Header="port" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Width="80"
|
||||
Binding="{Binding protocols}"
|
||||
Header="protocol" />
|
||||
<DataGridTextColumn
|
||||
@@ -318,11 +318,15 @@
|
||||
Binding="{Binding inboundTags}"
|
||||
Header="inboundTag" />
|
||||
<DataGridTextColumn
|
||||
Width="220"
|
||||
Width="90"
|
||||
Binding="{Binding network}"
|
||||
Header="network" />
|
||||
<DataGridTextColumn
|
||||
Width="190"
|
||||
Binding="{Binding domains}"
|
||||
Header="domain" />
|
||||
<DataGridTextColumn
|
||||
Width="220"
|
||||
Width="190"
|
||||
Binding="{Binding ips}"
|
||||
Header="ip" />
|
||||
<DataGridTextColumn
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.ViewModels;
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ApplicationIcon>v2rayN.ico</ApplicationIcon>
|
||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||
<FileVersion>6.45</FileVersion>
|
||||
<FileVersion>6.47</FileVersion>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Downloader" Version="3.0.6" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="5.0.0" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="5.1.0" />
|
||||
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.0.131" />
|
||||
<PackageReference Include="QRCoder.Xaml" Version="1.5.1" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
@@ -24,7 +24,7 @@
|
||||
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageReference Include="ReactiveUI.Validation" Version="4.0.9" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="20.0.1" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="20.1.1" />
|
||||
<PackageReference Include="Splat.NLog" Version="15.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user