using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Netch.Models; using Netch.ServerEx.ShadowsocksR.Form; using Netch.Utils; using Newtonsoft.Json.Linq; namespace Netch.ServerEx.ShadowsocksR { public class SSRUtil : IServerUtil { public ushort Priority { get; } = 1; public string TypeName { get; } = "SSR"; public string FullName { get; } = "ShadowsocksR"; public string[] UriScheme { get; } = {"ssr"}; public Server ParseJObject(JObject j) { return j.ToObject(); } public void Edit(Server s) { new ShadowsocksRForm(s).ShowDialog(); } public void Create() { new ShadowsocksRForm().ShowDialog(); } public string GetShareLink(Server s) { var server = (ShadowsocksR) s; // https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme // ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0) var paraStr = $"/?obfsparam={ShareLink.URLSafeBase64Encode(server.OBFSParam)}&protoparam={ShareLink.URLSafeBase64Encode(server.ProtocolParam)}&remarks={ShareLink.URLSafeBase64Encode(server.Remark)}"; return "ssr://" + ShareLink.URLSafeBase64Encode($"{server.Hostname}:{server.Port}:{server.Protocol}:{server.EncryptMethod}:{server.OBFS}:{ShareLink.URLSafeBase64Encode(server.Password)}{paraStr}"); } public ServerController GetController() { return new SSRController(); } /// /// SSR链接解析器 /// Copy From https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428 /// Thx :D /// /// /// public IEnumerable ParseUri(string text) { // ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1 var ssr = Regex.Match(text, "ssr://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase); if (!ssr.Success) throw new FormatException(); var data = ShareLink.URLSafeBase64Decode(ssr.Groups[1].Value); var paramsDict = new Dictionary(); var paramStartPos = data.IndexOf("?", StringComparison.Ordinal); if (paramStartPos > 0) { paramsDict = ShareLink.ParseParam(data.Substring(paramStartPos + 1)); data = data.Substring(0, paramStartPos); } if (data.IndexOf("/", StringComparison.Ordinal) >= 0) data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal)); var urlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)"); var match = urlFinder.Match(data); if (match == null || !match.Success) throw new FormatException(); var serverAddr = match.Groups[1].Value; var serverPort = ushort.Parse(match.Groups[2].Value); var protocol = match.Groups[3].Value.Length == 0 ? "origin" : match.Groups[3].Value; protocol = protocol.Replace("_compatible", ""); var method = match.Groups[4].Value; var obfs = match.Groups[5].Value.Length == 0 ? "plain" : match.Groups[5].Value; obfs = obfs.Replace("_compatible", ""); var password = ShareLink.URLSafeBase64Decode(match.Groups[6].Value); var protocolParam = ""; var obfsParam = ""; var remarks = ""; if (paramsDict.ContainsKey("protoparam")) protocolParam = ShareLink.URLSafeBase64Decode(paramsDict["protoparam"]); if (paramsDict.ContainsKey("obfsparam")) obfsParam = ShareLink.URLSafeBase64Decode(paramsDict["obfsparam"]); if (paramsDict.ContainsKey("remarks")) remarks = ShareLink.URLSafeBase64Decode(paramsDict["remarks"]); var group = paramsDict.ContainsKey("group") ? ShareLink.URLSafeBase64Decode(paramsDict["group"]) : string.Empty; return new[] { new ShadowsocksR { Hostname = serverAddr, Port = serverPort, Protocol = protocol, EncryptMethod = method, OBFS = obfs, Password = password, ProtocolParam = protocolParam, OBFSParam = obfsParam, Remark = remarks, Group = group } }; } public bool CheckServer(Server s) { var server = (ShadowsocksR) s; if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod)) { Logging.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}"); return false; } if (!SSRGlobal.Protocols.Contains(server.Protocol)) { Logging.Error($"不支持的 SSR 协议:{server.Protocol}"); return false; } if (!SSRGlobal.OBFSs.Contains(server.OBFS)) { Logging.Error($"不支持的 SSR 混淆:{server.OBFS}"); return false; } return true; } } }