diff --git a/Shadowsocks.WPF/Services/Sip003Plugin.cs b/Shadowsocks.WPF/Services/Sip003Plugin.cs index c57f6127..652b2fca 100644 --- a/Shadowsocks.WPF/Services/Sip003Plugin.cs +++ b/Shadowsocks.WPF/Services/Sip003Plugin.cs @@ -41,7 +41,7 @@ namespace Shadowsocks.WPF.Services showPluginOutput); } - private Sip003Plugin(string plugin, string pluginOpts, List pluginArgs, string serverAddress, int serverPort, bool showPluginOutput) + private Sip003Plugin(string plugin, string? pluginOpts, List? pluginArgs, string serverAddress, int serverPort, bool showPluginOutput) { if (plugin == null) throw new ArgumentNullException(nameof(plugin)); if (string.IsNullOrWhiteSpace(serverAddress)) @@ -50,7 +50,7 @@ namespace Shadowsocks.WPF.Services } if (serverPort <= 0 || serverPort > 65535) { - throw new ArgumentOutOfRangeException("serverPort"); + throw new ArgumentOutOfRangeException(nameof(serverPort)); } var pluginProcessStartInfo = new ProcessStartInfo @@ -68,8 +68,9 @@ namespace Shadowsocks.WPF.Services ["SS_PLUGIN_OPTIONS"] = pluginOpts } }; - foreach (var arg in pluginArgs) - pluginProcessStartInfo.ArgumentList.Add(arg); + if (pluginArgs != null) + foreach (var arg in pluginArgs) + pluginProcessStartInfo.ArgumentList.Add(arg); _pluginProcess = new Process() { @@ -119,7 +120,7 @@ namespace Shadowsocks.WPF.Services return true; } - public string ExpandEnvironmentVariables(string name, StringDictionary? environmentVariables = null) + public static string ExpandEnvironmentVariables(string name, StringDictionary? environmentVariables = null) { // Expand the environment variables from the new process itself if (environmentVariables != null) @@ -134,11 +135,11 @@ namespace Shadowsocks.WPF.Services return name; } - static int GetNextFreeTcpPort() + public static int GetNextFreeTcpPort() { var l = new TcpListener(IPAddress.Loopback, 0); l.Start(); - int port = ((IPEndPoint)l.LocalEndpoint).Port; + var port = ((IPEndPoint)l.LocalEndpoint).Port; l.Stop(); return port; } diff --git a/Shadowsocks/Models/Group.cs b/Shadowsocks/Models/Group.cs index ad817d28..50b09265 100644 --- a/Shadowsocks/Models/Group.cs +++ b/Shadowsocks/Models/Group.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using System.Text.Json.Serialization; namespace Shadowsocks.Models @@ -27,12 +26,14 @@ namespace Shadowsocks.Models /// Gets or sets the data usage in bytes. /// The value is fetched from SIP008 provider. /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong BytesUsed { get; set; } /// /// Gets or sets the data remaining to be used in bytes. /// The value is fetched from SIP008 provider. /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong BytesRemaining { get; set; } public Group() : this(string.Empty) diff --git a/Shadowsocks/Models/IServer.cs b/Shadowsocks/Models/IServer.cs index 82cdcf9f..2b232e0a 100644 --- a/Shadowsocks/Models/IServer.cs +++ b/Shadowsocks/Models/IServer.cs @@ -31,13 +31,13 @@ namespace Shadowsocks.Models /// Gets or sets the plugin executable filename. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string Plugin { get; set; } + public string? Plugin { get; set; } /// /// Gets or sets the plugin options passed as environment variables. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string PluginOpts { get; set; } + public string? PluginOpts { get; set; } /// /// Gets or sets the server name. diff --git a/Shadowsocks/Models/Server.cs b/Shadowsocks/Models/Server.cs index 6f9c276c..34f64e31 100644 --- a/Shadowsocks/Models/Server.cs +++ b/Shadowsocks/Models/Server.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using System.Text.Json.Serialization; namespace Shadowsocks.Models @@ -23,17 +22,17 @@ namespace Shadowsocks.Models /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string Plugin { get; set; } + public string? Plugin { get; set; } /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public string PluginOpts { get; set; } + public string? PluginOpts { get; set; } /// /// Gets or sets the arguments passed to the plugin process. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public List PluginArgs { get; set; } + public List? PluginArgs { get; set; } /// [JsonPropertyName("remarks")] @@ -49,9 +48,6 @@ namespace Shadowsocks.Models Port = 8388; Password = ""; Method = "chacha20-ietf-poly1305"; - Plugin = ""; - PluginOpts = ""; - PluginArgs = new(); Name = ""; Uuid = ""; } @@ -66,7 +62,7 @@ namespace Shadowsocks.Models /// public Uri ToUrl() { - UriBuilder uriBuilder = new UriBuilder("ss", Host, Port) + UriBuilder uriBuilder = new("ss", Host, Port) { UserName = Utilities.Base64Url.Encode($"{Method}:{Password}"), Fragment = Name, @@ -99,17 +95,20 @@ namespace Shadowsocks.Models var userinfoSplitArray = userinfo.Split(':', 2); var method = userinfoSplitArray[0]; var password = userinfoSplitArray[1]; + var host = uri.HostNameType == UriHostNameType.IPv6 ? uri.Host[1..^1] : uri.Host; + var escapedFragment = string.IsNullOrEmpty(uri.Fragment) ? uri.Fragment : uri.Fragment[1..]; + var name = Uri.UnescapeDataString(escapedFragment); server = new Server() { - Name = uri.Fragment, + Name = name, Uuid = new Guid().ToString(), - Host = uri.Host, + Host = host, Port = uri.Port, Password = password, Method = method, }; // find the plugin query - var parsedQueriesArray = uri.Query.Split("?&"); + var parsedQueriesArray = uri.Query.Split('?', '&'); var pluginQueryContent = ""; foreach (var query in parsedQueriesArray) { @@ -118,9 +117,15 @@ namespace Shadowsocks.Models pluginQueryContent = query[7..]; // remove "plugin=" } } + if (string.IsNullOrEmpty(pluginQueryContent)) // no plugin + return true; var unescapedpluginQuery = Uri.UnescapeDataString(pluginQueryContent); var parsedPluginQueryArray = unescapedpluginQuery.Split(';', 2); - if (parsedPluginQueryArray.Length == 2) // is valid plugin query + if (parsedPluginQueryArray.Length == 1) + { + server.Plugin = parsedPluginQueryArray[0]; + } + else if (parsedPluginQueryArray.Length == 2) // is valid plugin query { server.Plugin = parsedPluginQueryArray[0]; server.PluginOpts = parsedPluginQueryArray[1]; @@ -129,7 +134,7 @@ namespace Shadowsocks.Models } catch { - server = new Server(); + server = new(); return false; } } diff --git a/Shadowsocks/Utilities/Base64Url.cs b/Shadowsocks/Utilities/Base64Url.cs index 16b993ac..207c4efb 100644 --- a/Shadowsocks/Utilities/Base64Url.cs +++ b/Shadowsocks/Utilities/Base64Url.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Text; namespace Shadowsocks.Utilities @@ -14,7 +13,7 @@ namespace Shadowsocks.Utilities public static byte[] DecodeToBytes(string base64url) { - string base64string = base64url.Replace('_', '/').Replace('-', '+'); + var base64string = base64url.Replace('_', '/').Replace('-', '+'); base64string = base64string.PadRight(base64string.Length + (4 - base64string.Length % 4) % 4, '='); return Convert.FromBase64String(base64string); }