示例#1
0
        /**
         * start with "ss://".
         * Reference code:
         * https://github.com/shadowsocks/shadowsocks-windows/raw/master/shadowsocks-csharp/Model/Server.cs
         */
        public static ServerProfile ParseLegacyServer(string ssUrl)
        {
            var match = UrlFinder.Match(ssUrl);

            if (!match.Success)
            {
                return(null);
            }

            ServerProfile serverProfile = new ServerProfile();
            var           base64        = match.Groups["base64"].Value.TrimEnd('/');
            var           tag           = match.Groups["tag"].Value;

            if (!string.IsNullOrEmpty(tag))
            {
                serverProfile.vRemarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
            }

            Match details = null;

            try
            {
                details = DetailsParser.Match(
                    Encoding.UTF8.GetString(Convert.FromBase64String(base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
            }
            catch (FormatException)
            {
                return(null);
            }

            if (!details.Success)
            {
                return(null);
            }

            serverProfile.vEncrypt  = details.Groups["method"].Value;
            serverProfile.vPassword = details.Groups["password"].Value;
            serverProfile.vHostIP   = details.Groups["hostname"].Value;
            serverProfile.vPort     = int.Parse(details.Groups["port"].Value);

            serverProfile.SetFriendlyNameDefault();
            return(serverProfile);
        }
示例#2
0
        public Server(string ssUrl)
        {
            if (!ssUrl.StartsWith("ss://", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("Invalid");
            }
            if (ssUrl.EndsWith("/?outline=1", StringComparison.OrdinalIgnoreCase))
            {
                var outline = OutlineFinder.Match(ssUrl);
                if (outline.Success)
                {
                    var base64 = outline.Groups["base64"].Value.TrimEnd('/');
                    var spl    = base64.DeBase64().Split(':');
                    if (spl.Length == 2)
                    {
                        method      = spl[0];
                        password    = spl[1];
                        server      = outline.Groups["hostname"].Value;
                        server_port = int.Parse(outline.Groups["port"].Value);
                        timeout     = DefaultServerTimeoutSec;
                        Logging.Info("Parse Outline Server:" + FriendlyName());
                        return;
                    }
                }
            }

            if (UriFinder.IsMatch(ssUrl))
            {//new format
                Uri parsedUrl;
                try
                {
                    parsedUrl = new Uri(ssUrl);
                }
                catch (UriFormatException)
                {
                    throw new Exception("Invalid");
                }
                remarks     = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
                server      = parsedUrl.GetComponents(UriComponents.Host, UriFormat.Unescaped);
                server_port = parsedUrl.Port;

                var    rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
                var    base64      = rawUserInfo.Replace('-', '+').Replace('_', '/'); // Web-safe base64 to normal base64
                string userInfo;
                try
                {
                    userInfo = base64.DeBase64();
                }
                catch (FormatException)
                {
                    throw new Exception("Invalid");
                }
                var userInfoParts = userInfo.Split(new[] { ':' }, 2);
                if (userInfoParts.Length != 2)
                {
                    throw new Exception("Invalid");
                }
                method   = userInfoParts[0];
                password = userInfoParts[1];

                var queryParameters = new NameValueCollection();
                if (parsedUrl.Query.StartsWith("?"))
                {
                    var queryString = parsedUrl.Query.Substring(1, parsedUrl.Query.Length - 1);
                    foreach (string element in queryString.Split('&'))
                    {
                        string[] pair = element.Split('=');
                        if (pair.Length == 2)
                        {
                            string name  = Uri.UnescapeDataString(pair[0]);
                            string value = Uri.UnescapeDataString(pair[1]);
                            queryParameters.Add(name, value);
                        }
                    }
                }
                var pluginParts = (queryParameters["plugin"] ?? "").Split(new[] { ';' }, 2);
                if (pluginParts.Length > 0)
                {
                    plugin = pluginParts[0] ?? "";
                }

                if (pluginParts.Length > 1)
                {
                    plugin_opts = pluginParts[1] ?? "";
                }
                timeout = DefaultServerTimeoutSec;
                Logging.Info("Parse Server:" + FriendlyName());
            }
            else
            {
                var matchOld = UrlFinder.Match(ssUrl);
                if (matchOld.Success)
                {
                    var base64 = matchOld.Groups["base64"].Value.TrimEnd('/');
                    var tag    = matchOld.Groups["tag"].Value;
                    if (!string.IsNullOrEmpty(tag))
                    {
                        remarks = Uri.UnescapeDataString(tag);
                    }
                    Match details;
                    try
                    {
                        details = DetailsParser.Match(base64.DeBase64());
                    }
                    catch (FormatException)
                    {
                        throw new Exception("Invalid");
                    }
                    if (!details.Success)
                    {
                        throw new Exception("Invalid");
                    }
                    method      = details.Groups["method"].Value;
                    password    = details.Groups["password"].Value;
                    server      = details.Groups["hostname"].Value;
                    server_port = int.Parse(details.Groups["port"].Value);
                    timeout     = DefaultServerTimeoutSec;
                    Logging.Info("Parse Classic Server:" + FriendlyName());
                }
                else
                {
                    throw new FormatException("ParseFail:" + ssUrl);
                }
            }
        }