@@ -41,7 +41,7 @@ namespace Shadowsocks.WPF.Services | |||
showPluginOutput); | |||
} | |||
private Sip003Plugin(string plugin, string pluginOpts, List<string> pluginArgs, string serverAddress, int serverPort, bool showPluginOutput) | |||
private Sip003Plugin(string plugin, string? pluginOpts, List<string>? 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; | |||
} | |||
@@ -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. | |||
/// </summary> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public ulong BytesUsed { get; set; } | |||
/// <summary> | |||
/// Gets or sets the data remaining to be used in bytes. | |||
/// The value is fetched from SIP008 provider. | |||
/// </summary> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public ulong BytesRemaining { get; set; } | |||
public Group() : this(string.Empty) | |||
@@ -31,13 +31,13 @@ namespace Shadowsocks.Models | |||
/// Gets or sets the plugin executable filename. | |||
/// </summary> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public string Plugin { get; set; } | |||
public string? Plugin { get; set; } | |||
/// <summary> | |||
/// Gets or sets the plugin options passed as environment variables. | |||
/// </summary> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public string PluginOpts { get; set; } | |||
public string? PluginOpts { get; set; } | |||
/// <summary> | |||
/// Gets or sets the server name. | |||
@@ -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 | |||
/// <inheritdoc/> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public string Plugin { get; set; } | |||
public string? Plugin { get; set; } | |||
/// <inheritdoc/> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public string PluginOpts { get; set; } | |||
public string? PluginOpts { get; set; } | |||
/// <summary> | |||
/// Gets or sets the arguments passed to the plugin process. | |||
/// </summary> | |||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] | |||
public List<string> PluginArgs { get; set; } | |||
public List<string>? PluginArgs { get; set; } | |||
/// <inheritdoc/> | |||
[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 | |||
/// <returns></returns> | |||
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; | |||
} | |||
} | |||
@@ -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); | |||
} | |||