@@ -371,48 +371,7 @@ namespace Shadowsocks.Controller | |||||
public string GetServerURLForCurrentServer() | public string GetServerURLForCurrentServer() | ||||
{ | { | ||||
Server server = GetCurrentServer(); | |||||
return GetServerURL(server); | |||||
} | |||||
public static string GetServerURL(Server server) | |||||
{ | |||||
string tag = string.Empty; | |||||
string url = string.Empty; | |||||
if (string.IsNullOrWhiteSpace(server.plugin)) | |||||
{ | |||||
// For backwards compatiblity, if no plugin, use old url format | |||||
string parts = $"{server.method}:{server.password}@{server.server}:{server.server_port}"; | |||||
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)); | |||||
url = base64; | |||||
} | |||||
else | |||||
{ | |||||
// SIP002 | |||||
string parts = $"{server.method}:{server.password}"; | |||||
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)); | |||||
string websafeBase64 = base64.Replace('+', '-').Replace('/', '_').TrimEnd('='); | |||||
string pluginPart = server.plugin; | |||||
if (!string.IsNullOrWhiteSpace(server.plugin_opts)) | |||||
{ | |||||
pluginPart += ";" + server.plugin_opts; | |||||
} | |||||
url = string.Format( | |||||
"{0}@{1}:{2}/?plugin={3}", | |||||
websafeBase64, | |||||
server.FormatHostName(server.server), | |||||
server.server_port, | |||||
HttpUtility.UrlEncode(pluginPart, Encoding.UTF8)); | |||||
} | |||||
if (!server.remarks.IsNullOrEmpty()) | |||||
{ | |||||
tag = $"#{HttpUtility.UrlEncode(server.remarks, Encoding.UTF8)}"; | |||||
} | |||||
return $"ss://{url}{tag}"; | |||||
return GetCurrentServer().URL; | |||||
} | } | ||||
public void UpdatePACFromGeosite() | public void UpdatePACFromGeosite() | ||||
@@ -50,21 +50,67 @@ namespace Shadowsocks.Model | |||||
return I18N.GetString("New server"); | return I18N.GetString("New server"); | ||||
} | } | ||||
string serverStr = $"{FormatHostName(server)}:{server_port}"; | |||||
string serverStr = $"{FormalHostName}:{server_port}"; | |||||
return remarks.IsNullOrEmpty() | return remarks.IsNullOrEmpty() | ||||
? serverStr | ? serverStr | ||||
: $"{remarks} ({serverStr})"; | : $"{remarks} ({serverStr})"; | ||||
} | } | ||||
public string FormatHostName(string hostName) | |||||
public string URL | |||||
{ | { | ||||
// CheckHostName() won't do a real DNS lookup | |||||
switch (Uri.CheckHostName(hostName)) | |||||
get | |||||
{ | { | ||||
case UriHostNameType.IPv6: // Add square bracket when IPv6 (RFC3986) | |||||
return $"[{hostName}]"; | |||||
default: // IPv4 or domain name | |||||
return hostName; | |||||
string tag = string.Empty; | |||||
string url = string.Empty; | |||||
if (string.IsNullOrWhiteSpace(plugin)) | |||||
{ | |||||
// For backwards compatiblity, if no plugin, use old url format | |||||
string parts = $"{method}:{password}@{server}:{server_port}"; | |||||
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)); | |||||
url = base64; | |||||
} | |||||
else | |||||
{ | |||||
// SIP002 | |||||
string parts = $"{method}:{password}"; | |||||
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)); | |||||
string websafeBase64 = base64.Replace('+', '-').Replace('/', '_').TrimEnd('='); | |||||
string pluginPart = plugin; | |||||
if (!string.IsNullOrWhiteSpace(plugin_opts)) | |||||
{ | |||||
pluginPart += ";" + plugin_opts; | |||||
} | |||||
url = string.Format( | |||||
"{0}@{1}:{2}/?plugin={3}", | |||||
websafeBase64, | |||||
FormalHostName, | |||||
server_port, | |||||
HttpUtility.UrlEncode(pluginPart, Encoding.UTF8)); | |||||
} | |||||
if (!remarks.IsNullOrEmpty()) | |||||
{ | |||||
tag = $"#{HttpUtility.UrlEncode(remarks, Encoding.UTF8)}"; | |||||
} | |||||
return $"ss://{url}{tag}"; | |||||
} | |||||
} | |||||
public string FormalHostName | |||||
{ | |||||
get | |||||
{ | |||||
// CheckHostName() won't do a real DNS lookup | |||||
switch (Uri.CheckHostName(server)) | |||||
{ | |||||
case UriHostNameType.IPv6: // Add square bracket when IPv6 (RFC3986) | |||||
return $"[{server}]"; | |||||
default: // IPv4 or domain name | |||||
return server; | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -67,7 +67,7 @@ namespace Shadowsocks.View | |||||
var servers = Configuration.Load(); | var servers = Configuration.Load(); | ||||
var serverDatas = servers.configs.Select( | var serverDatas = servers.configs.Select( | ||||
server => | server => | ||||
new KeyValuePair<string, string>(ShadowsocksController.GetServerURL(server), server.ToString()) | |||||
new KeyValuePair<string, string>(server.URL, server.ToString()) | |||||
).ToList(); | ).ToList(); | ||||
listBox1.DataSource = serverDatas; | listBox1.DataSource = serverDatas; | ||||
@@ -243,7 +243,7 @@ namespace Shadowsocks.Test | |||||
string expected = testCase.Key; | string expected = testCase.Key; | ||||
Server config = testCase.Value; | Server config = testCase.Value; | ||||
var actual = ShadowsocksController.GetServerURL(config); | |||||
var actual = config.URL; | |||||
Assert.AreEqual(expected, actual); | Assert.AreEqual(expected, actual); | ||||
} | } | ||||
} | } | ||||