Feat #517 new VMess/VLESS ShareLink format get and parse

This commit is contained in:
ChsBuffer
2021-02-16 20:02:07 +08:00
parent eac456b3a8
commit 8f8fa159c7
7 changed files with 267 additions and 144 deletions

View File

@@ -3,106 +3,16 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Shadowsocks.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Server = Netch.Models.Server;
namespace Netch.Utils
{
public static class ShareLink
{
#region Utils
/// <summary>
/// URL 传输安全的 Base64 解码
/// </summary>
/// <param name="text">需要解码的字符串</param>
/// <returns>解码后的字符串</returns>
public static string URLSafeBase64Decode(string text)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
}
/// <summary>
/// URL 传输安全的 Base64 加密
/// </summary>
/// <param name="text">需要加密的字符串</param>
/// <returns>加密后的字符串</returns>
public static string URLSafeBase64Encode(string text)
{
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
private static string RemoveEmoji(string text)
{
byte[] emojiBytes = {240, 159};
var remark = Encoding.UTF8.GetBytes(text);
var startIndex = 0;
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])
startIndex += 4;
return Encoding.UTF8.GetString(remark.Skip(startIndex).ToArray()).Trim();
}
public static string UnBase64String(string value)
{
if (string.IsNullOrEmpty(value))
{
return "";
}
var bytes = Convert.FromBase64String(value);
return Encoding.UTF8.GetString(bytes);
}
public static string ToBase64String(string value)
{
if (string.IsNullOrEmpty(value))
{
return "";
}
var bytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(bytes);
}
public static Dictionary<string, string> ParseParam(string paramStr)
{
var paramsDict = new Dictionary<string, string>();
var obfsParams = paramStr.Split('&');
foreach (var p in obfsParams)
{
if (p.IndexOf('=') > 0)
{
var index = p.IndexOf('=');
var key = p.Substring(0, index);
var val = p.Substring(index + 1);
paramsDict[key] = val;
}
}
return paramsDict;
}
public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = true)
{
using var sr = new StringReader(str);
string line;
while ((line = sr.ReadLine()) != null)
{
if (removeEmptyLines && string.IsNullOrWhiteSpace(line))
{
continue;
}
yield return line;
}
}
#endregion
public static string GetShareLink(Server server)
{
return ServerHelper.GetUtilByTypeName(server.Type).GetShareLink(server);
@@ -137,9 +47,7 @@ namespace Netch.Utils
catch (JsonReaderException)
{
foreach (var line in text.GetLines())
{
list.AddRange(ParseUri(line));
}
}
catch (Exception e)
{
@@ -168,13 +76,9 @@ namespace Netch.Utils
var scheme = GetUriScheme(text);
var util = ServerHelper.GetUtilByUriScheme(scheme);
if (util != null)
{
list.AddRange(util.ParseUri(text));
}
else
{
Logging.Warning($"无法处理 {scheme} 协议订阅链接");
}
}
}
catch (Exception e)
@@ -183,14 +87,13 @@ namespace Netch.Utils
}
foreach (var node in list)
{
node.Remark = RemoveEmoji(node.Remark);
}
if (!node.Remark.IsNullOrWhiteSpace())
node.Remark = RemoveEmoji(node.Remark);
return list.Where(s => s != null);
}
private static string GetUriScheme(string text)
public static string GetUriScheme(string text)
{
var endIndex = text.IndexOf("://", StringComparison.Ordinal);
if (endIndex == -1)
@@ -206,19 +109,13 @@ namespace Netch.Utils
var NetchLink = (JObject) JsonConvert.DeserializeObject(URLSafeBase64Decode(text));
if (NetchLink == null)
{
return null;
}
if (string.IsNullOrEmpty((string) NetchLink["Hostname"]))
{
return null;
}
if (!ushort.TryParse((string) NetchLink["Port"], out _))
{
return null;
}
var type = (string) NetchLink["Type"];
var s = ServerHelper.GetUtilByTypeName(type).ParseJObject(NetchLink);
@@ -236,5 +133,86 @@ namespace Netch.Utils
var server = (Server) s.Clone();
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(server, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
}
#region Utils
/// <summary>
/// URL 传输安全的 Base64 解码
/// </summary>
/// <param name="text">需要解码的字符串</param>
/// <returns>解码后的字符串</returns>
public static string URLSafeBase64Decode(string text)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
}
/// <summary>
/// URL 传输安全的 Base64 加密
/// </summary>
/// <param name="text">需要加密的字符串</param>
/// <returns>加密后的字符串</returns>
public static string URLSafeBase64Encode(string text)
{
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
private static string RemoveEmoji(string text)
{
byte[] emojiBytes = {240, 159};
var remark = Encoding.UTF8.GetBytes(text);
var startIndex = 0;
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])
startIndex += 4;
return Encoding.UTF8.GetString(remark.Skip(startIndex).ToArray()).Trim();
}
public static string UnBase64String(string value)
{
if (string.IsNullOrEmpty(value))
return "";
var bytes = Convert.FromBase64String(value);
return Encoding.UTF8.GetString(bytes);
}
public static string ToBase64String(string value)
{
if (string.IsNullOrEmpty(value))
return "";
var bytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(bytes);
}
public static Dictionary<string, string> ParseParam(string paramStr)
{
var paramsDict = new Dictionary<string, string>();
var obfsParams = paramStr.Split('&');
foreach (var p in obfsParams)
if (p.IndexOf('=') > 0)
{
var index = p.IndexOf('=');
var key = p.Substring(0, index);
var val = p.Substring(index + 1);
paramsDict[key] = val;
}
return paramsDict;
}
public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = true)
{
using var sr = new StringReader(str);
string line;
while ((line = sr.ReadLine()) != null)
{
if (removeEmptyLines && string.IsNullOrWhiteSpace(line))
continue;
yield return line;
}
}
#endregion
}
}