You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Server.cs 4.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.Json.Serialization;
  5. namespace Shadowsocks.Models
  6. {
  7. public class Server : IServer
  8. {
  9. [JsonPropertyName("server")]
  10. public string Host { get; set; }
  11. [JsonPropertyName("server_port")]
  12. public int Port { get; set; }
  13. public string Password { get; set; }
  14. public string Method { get; set; }
  15. public string Plugin { get; set; }
  16. public string PluginOpts { get; set; }
  17. [JsonPropertyName("remarks")]
  18. public string Name { get; set; }
  19. [JsonPropertyName("id")]
  20. public string Uuid { get; set; }
  21. public Server()
  22. {
  23. Host = "";
  24. Port = 8388;
  25. Password = "";
  26. Method = "chacha20-ietf-poly1305";
  27. Plugin = "";
  28. PluginOpts = "";
  29. Name = "";
  30. Uuid = "";
  31. }
  32. public Server(
  33. string name,
  34. string uuid,
  35. string host,
  36. int port,
  37. string password,
  38. string method,
  39. string plugin = "",
  40. string pluginOpts = "")
  41. {
  42. Host = host;
  43. Port = port;
  44. Password = password;
  45. Method = method;
  46. Plugin = plugin;
  47. PluginOpts = pluginOpts;
  48. Name = name;
  49. Uuid = uuid;
  50. }
  51. public bool Equals(IServer? other) => other is Server anotherServer && Uuid == anotherServer.Uuid;
  52. public override int GetHashCode() => Uuid.GetHashCode();
  53. public override string ToString() => Name;
  54. /// <summary>
  55. /// Converts this server object into an ss:// URL.
  56. /// </summary>
  57. /// <returns></returns>
  58. public Uri ToUrl()
  59. {
  60. UriBuilder uriBuilder = new UriBuilder("ss", Host, Port)
  61. {
  62. UserName = Utilities.Base64Url.Encode($"{Method}:{Password}"),
  63. Fragment = Name,
  64. };
  65. if (!string.IsNullOrEmpty(Plugin))
  66. if (!string.IsNullOrEmpty(PluginOpts))
  67. uriBuilder.Query = $"plugin={Uri.EscapeDataString($"{Plugin};{PluginOpts}")}"; // manually escape as a workaround
  68. else
  69. uriBuilder.Query = $"plugin={Plugin}";
  70. return uriBuilder.Uri;
  71. }
  72. /// <summary>
  73. /// Tries to parse an ss:// URL into a Server object.
  74. /// </summary>
  75. /// <param name="url">The ss:// URL to parse.</param>
  76. /// <param name="server">
  77. /// A Server object represented by the URL.
  78. /// A new empty Server object if the URL is invalid.</param>
  79. /// <returns>True for success. False for failure.</returns>
  80. public static bool TryParse(string url, out Server server)
  81. {
  82. try
  83. {
  84. var uri = new Uri(url);
  85. if (uri.Scheme != "ss")
  86. throw new ArgumentException("Wrong URL scheme");
  87. var userinfo_base64url = uri.UserInfo;
  88. var userinfo = Utilities.Base64Url.DecodeToString(userinfo_base64url);
  89. var userinfoSplitArray = userinfo.Split(':', 2);
  90. var method = userinfoSplitArray[0];
  91. var password = userinfoSplitArray[1];
  92. server = new Server(uri.Fragment, new Guid().ToString(), uri.Host, uri.Port, password, method);
  93. // find the plugin query
  94. var parsedQueriesArray = uri.Query.Split("?&");
  95. var pluginQueryContent = "";
  96. foreach (var query in parsedQueriesArray)
  97. {
  98. if (query.StartsWith("plugin=") && query.Length > 7)
  99. {
  100. pluginQueryContent = query[7..]; // remove "plugin="
  101. }
  102. }
  103. var unescapedpluginQuery = Uri.UnescapeDataString(pluginQueryContent);
  104. var parsedPluginQueryArray = unescapedpluginQuery.Split(';', 2);
  105. if (parsedPluginQueryArray.Length == 2) // is valid plugin query
  106. {
  107. server.Plugin = parsedPluginQueryArray[0];
  108. server.PluginOpts = parsedPluginQueryArray[1];
  109. }
  110. return true;
  111. }
  112. catch
  113. {
  114. server = new Server();
  115. return false;
  116. }
  117. }
  118. }
  119. }