Compare commits

...
36 Commits
Author SHA1 Message Date
celeron533 0c877a76c6 Update CHANGES and bump version 2017-12-09 12:24:23 +08:00
celeron533 c24714e168 Simplify SystemEvents_PowerModeChanged() 2017-12-03 21:11:41 +08:00
celeron533 46d40fec67 Add the UserRule at the beginning of PAC file 2017-11-19 13:57:27 +08:00
Allen Zhu aacc4edf69 Merge pull request #1438 from SharerMax/master
Add option to show password
2017-11-18 22:22:57 -06:00
SharerMax acc192df34 Remove useless code 2017-10-11 01:04:55 +08:00
SharerMax eae0b1cfac Add option to show password 2017-10-11 01:00:24 +08:00
Allen Zhu 63980b3a12 Merge pull request #1406 from celeron533/SIP002_Refine
Sip002 refine
2017-10-05 05:43:12 -05:00
celeron533 a4c4967f5f Rename GetQRCode() to GetServerURL() 2017-09-25 20:24:15 +08:00
celeron533 55c19187c7 Refine URL parser
- Bring back the legacy parser
- Refine SIP002 logic
2017-09-25 20:24:15 +08:00
celeron533 7c73aaa1cf Append more test cases for ParseShadowsocksUrlTest 2017-09-10 10:55:45 +08:00
celeron533 77a93a9140 Fix the issue "unable to add server from URL"
Base64 code ended with '=' cause the Uri invalid to parse.
Simplified the logic.
2017-09-10 00:54:39 +08:00
celeron533 08f06f7177 Update CHANGES and bump version 2017-09-09 20:24:50 +08:00
celeron533 cb3afafd54 Update readme.md 2017-09-08 21:54:38 +08:00
celeron533 05df449826 Add notification message 2017-09-05 22:31:54 +08:00
celeron533 d0e692a491 Translation for SIP003 2017-08-31 20:28:45 +08:00
Allen Zhu b0a2c2735b Merge pull request #1336 from rwasef1830/use_job_for_sip003_plugin
Use job objects with SIP003 plugin to avoid lingering processes if app is killed
2017-08-31 19:58:07 +08:00
Raif Atef f239244af2 Early start SIP003 plugins when reloading servers to avoid delay on first packet. 2017-08-27 09:11:41 +02:00
Raif Atef a316b95f45 Logging for SIP003 start failure. 2017-08-26 21:22:53 +02:00
Raif Atef cf5de91acb Use job objects with SIP003 plugin to avoid lingering processes if app is killed. 2017-08-23 12:36:32 +02:00
Allen Zhu 71120e5c3e Merge pull request #1298 from rwasef1830/sip003
SIP002 and SIP003 support.
2017-08-21 20:25:34 +08:00
Raif Atef caa96ad334 Fix port range check and move Sip003Plugin. 2017-08-17 11:11:06 +02:00
Raif Atef f04b497d79 SIP002 and SIP003 support 2017-08-14 11:48:41 +02:00
celeron533 ed31a3cab0 Update CHANGES and bump version 2017-08-09 19:20:50 +08:00
celeron533 081bbaf011 Fix #1301. Configuration is not fully initialized and cause NullReferenceException crash 2017-08-06 22:48:02 +08:00
celeron533 0251130fa5 Socket.ConnectAsync() does not call SocketAsyncEventArgs.Completed when operation completed synchronously.
#1273
2017-08-06 17:17:32 +08:00
Jacob Zuo f0b196c8c3 Fix "4.0.4 launch exception" error (PR #1232) 2017-08-06 12:06:29 +08:00
celeron533 057b148092 Merge pull request #1227 from gitzhuoer/patch-2
Add .NET Framework 4.6.2 requirement
2017-07-10 19:47:42 +08:00
Zhuoer Dong 101c33d0f1 Update README.md 2017-07-10 19:41:48 +08:00
Syrone Wong bbfc5d332d Update CHANGES and bump version
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2017-06-01 15:55:55 +08:00
Syrone Wong 5d75e19c26 prefer to use aes-256-gcm in libsodium
which is hardware accelerated compared to AES-GCM in mbedtls

We have to drop this commit when mbedtls support hw-accelerated GCM
when compiling with MSVC

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2017-05-31 10:04:00 +08:00
Syrone Wong 816651ebdc Save user wininet settings as another config file 2017-05-25 17:18:20 +08:00
Syrone Wong 44afefed71 Update CHANGES and bump version
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2017-05-19 16:47:31 +08:00
Syrone Wong 2eeebc29d7 Replace circular buffer with the blockcopy variant
to get rid of deep copy

- update NuGet pkg

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2017-05-19 15:56:13 +08:00
Ninedyz 0e01f8303c update Japanese translation (#1138)
* Update ja.txt

* Update ja.txt

* Update ja.txt

Sorry for the multiple posts(´・ω・`)

* Update ja.txt

* Update ja.txt
2017-05-19 06:20:30 +08:00
Syrone Wong 2fcf843bba libsodium: enable AVX2 for x86
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2017-05-15 16:14:37 +08:00
Syrone Wong 3b3a8c9077 fix legacy key derivation 2017-04-21 12:39:53 +08:00
34 changed files with 1733 additions and 407 deletions
+22
View File
@@ -1,3 +1,25 @@
4.0.7 2017-12-09
- Fix QR code and ss:// protocol import issue
- Add an option to show password
- User rules have higher priority in PAC file
- Bug fixes and improvements
4.0.6 2017-09-09
- SIP002 support
- SIP003 support
4.0.5 2017-08-09
- Fix crash when user-wininet.json fail to parse. (#1178)
- Bug fixes and improvements.
4.0.4 2017-06-01
- Save user wininet settings as user-wininet.json
- Improve performance of aes-256-gcm
4.0.2 2017-05-19
- Fix legacy key derivation
- Bug fixes and improvements
4.0.1 2017-04-08
- Fix UDP relay
- Allow to add multiple servers via Shadowsocks URL
+16 -4
View File
@@ -13,11 +13,16 @@ Shadowsocks for Windows
4. Supports HTTP proxy
5. Supports server auto switching
6. Supports UDP relay (see Usage)
7. Supports plugins
#### Download
Download the [latest release].
#### Requirements
Microsoft [.NET Framework 4.6.2] or higher.
#### Basic
1. Find Shadowsocks icon in the notification tray
@@ -54,11 +59,17 @@ If you want to manage multiple servers using other tools like SwitchyOmega,
you can start multiple Shadowsocks instances. To avoid configuration conflicts,
copy Shadowsocks to a new directory and choose a different local port.
#### Plugins
If you would like to connect to server via a plugin, please set the plugin's
path (relative or absolute) on Edit Servers form.
Note: Forward Proxy will not be used while a plugin is enabled.
#### Global hotkeys
Hotkeys are NOT registered automatically. You should re-register all hotkeys after
restarting Shadowsocks. If you are using multiple instances of Shadowsocks,
you must set different key combination for other instances.
you must set different key combination for each instance.
##### How to input?
@@ -98,11 +109,12 @@ Please visit [Servers] for more information.
GPLv3
[Appveyor]: https://ci.appveyor.com/project/wongsyrone/shadowsocks-windows-yqdou
[Build Status]: https://ci.appveyor.com/api/projects/status/yieb7lo96irmuc28/branch/master?svg=true
[Appveyor]: https://ci.appveyor.com/project/celeron533/shadowsocks-windows
[Build Status]: https://ci.appveyor.com/api/projects/status/tfw57q6eecippsl5/branch/master?svg=true
[latest release]: https://github.com/shadowsocks/shadowsocks-csharp/releases
[GFWList]: https://github.com/gfwlist/gfwlist
[Servers]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#linux--server-side
[中文说明]: https://github.com/shadowsocks/shadowsocks-windows/wiki/Shadowsocks-Windows-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
[.NET Framework 4.6.2]: https://www.microsoft.com/en-US/download/details.aspx?id=53344
[Visual Studio 2015]: https://www.visualstudio.com/downloads/
[.NET Framework 4.6.2 Developer Pack]: https://www.microsoft.com/download/details.aspx?id=53321
[.NET Framework 4.6.2 Developer Pack]: https://www.microsoft.com/download/details.aspx?id=53321
@@ -0,0 +1,140 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using Shadowsocks.Model;
using Shadowsocks.Util.ProcessManagement;
namespace Shadowsocks.Controller.Service
{
// https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin
public sealed class Sip003Plugin : IDisposable
{
public IPEndPoint LocalEndPoint { get; private set; }
public int ProcessId => _started ? _pluginProcess.Id : 0;
private readonly object _startProcessLock = new object();
private readonly Job _pluginJob;
private readonly Process _pluginProcess;
private bool _started;
private bool _disposed;
public static Sip003Plugin CreateIfConfigured(Server server)
{
if (server == null)
{
throw new ArgumentNullException(nameof(server));
}
if (string.IsNullOrWhiteSpace(server.plugin))
{
return null;
}
return new Sip003Plugin(server.plugin, server.plugin_opts, server.server, server.server_port);
}
private Sip003Plugin(string plugin, string pluginOpts, string serverAddress, int serverPort)
{
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
if (string.IsNullOrWhiteSpace(serverAddress))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(serverAddress));
}
if ((ushort)serverPort != serverPort)
{
throw new ArgumentOutOfRangeException("serverPort");
}
var appPath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath);
_pluginProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = plugin,
UseShellExecute = false,
CreateNoWindow = true,
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = appPath ?? Environment.CurrentDirectory,
Environment =
{
["SS_REMOTE_HOST"] = serverAddress,
["SS_REMOTE_PORT"] = serverPort.ToString(),
["SS_PLUGIN_OPTIONS"] = pluginOpts
}
}
};
_pluginJob = new Job();
}
public bool StartIfNeeded()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
lock (_startProcessLock)
{
if (_started && !_pluginProcess.HasExited)
{
return false;
}
var localPort = GetNextFreeTcpPort();
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort);
_pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString();
_pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString();
_pluginProcess.Start();
_pluginJob.AddProcess(_pluginProcess.Handle);
_started = true;
}
return true;
}
static int GetNextFreeTcpPort()
{
var l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
public void Dispose()
{
if (_disposed)
{
return;
}
try
{
if (!_pluginProcess.HasExited)
{
_pluginProcess.Kill();
_pluginProcess.WaitForExit();
}
}
catch (Exception) { }
finally
{
try
{
_pluginProcess.Dispose();
_pluginJob.Dispose();
}
catch (Exception) { }
_disposed = true;
}
}
}
}
@@ -570,7 +570,15 @@ namespace Shadowsocks.Controller
// Setting up proxy
IProxy remote;
EndPoint proxyEP = null;
if (_config.proxy.useProxy)
EndPoint serverEP = SocketUtil.GetEndPoint(_server.server, _server.server_port);
EndPoint pluginEP = _controller.GetPluginLocalEndPointIfConfigured(_server);
if (pluginEP != null)
{
serverEP = pluginEP;
remote = new DirectConnect();
}
else if (_config.proxy.useProxy)
{
switch (_config.proxy.proxyType)
{
@@ -607,7 +615,7 @@ namespace Shadowsocks.Controller
proxyTimer.Enabled = true;
proxyTimer.Session = session;
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(_server.server, _server.server_port);
proxyTimer.DestEndPoint = serverEP;
proxyTimer.Server = _server;
_proxyConnected = false;
@@ -24,7 +24,7 @@ namespace Shadowsocks.Controller
public string LatestVersionLocalName;
public event EventHandler CheckUpdateCompleted;
public const string Version = "4.0.1";
public const string Version = "4.0.7";
private class CheckUpdateTimer : System.Timers.Timer
{
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
@@ -14,6 +15,8 @@ using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using System.Linq;
using Shadowsocks.Controller.Service;
using Shadowsocks.Proxy;
namespace Shadowsocks.Controller
{
@@ -33,6 +36,8 @@ namespace Shadowsocks.Controller
private StrategyManager _strategyManager;
private PrivoxyRunner privoxyRunner;
private GFWListUpdater gfwListUpdater;
private readonly ConcurrentDictionary<Server, Sip003Plugin> _pluginsByServer;
public AvailabilityStatistics availabilityStatistics = AvailabilityStatistics.Instance;
public StatisticsStrategyConfiguration StatisticsConfiguration { get; private set; }
@@ -44,8 +49,6 @@ namespace Shadowsocks.Controller
private bool stopped = false;
private bool _systemProxyIsDirty = false;
public class PathEventArgs : EventArgs
{
public string Path;
@@ -81,6 +84,7 @@ namespace Shadowsocks.Controller
_config = Configuration.Load();
StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
_strategyManager = new StrategyManager(this);
_pluginsByServer = new ConcurrentDictionary<Server, Sip003Plugin>();
StartReleasingMemory();
StartTrafficStatistics(61);
}
@@ -146,6 +150,31 @@ namespace Shadowsocks.Controller
return GetCurrentServer();
}
public EndPoint GetPluginLocalEndPointIfConfigured(Server server)
{
var plugin = _pluginsByServer.GetOrAdd(server, Sip003Plugin.CreateIfConfigured);
if (plugin == null)
{
return null;
}
try
{
if (plugin.StartIfNeeded())
{
Logging.Info(
$"Started SIP003 plugin for {server.Identifier()} on {plugin.LocalEndPoint} - PID: {plugin.ProcessId}");
}
}
catch (Exception ex)
{
Logging.Error("Failed to start SIP003 plugin: " + ex.Message);
throw;
}
return plugin.LocalEndPoint;
}
public void SaveServers(List<Server> servers, int localPort)
{
_config.configs = servers;
@@ -261,6 +290,7 @@ namespace Shadowsocks.Controller
{
_listener.Stop();
}
StopPlugins();
if (privoxyRunner != null)
{
privoxyRunner.Stop();
@@ -272,6 +302,15 @@ namespace Shadowsocks.Controller
Encryption.RNG.Close();
}
private void StopPlugins()
{
foreach (var serverAndPlugin in _pluginsByServer)
{
serverAndPlugin.Value?.Dispose();
}
_pluginsByServer.Clear();
}
public void TouchPACFile()
{
string pacFilename = _pacServer.TouchPACFile();
@@ -290,22 +329,50 @@ namespace Shadowsocks.Controller
}
}
public string GetQRCodeForCurrentServer()
public string GetServerURLForCurrentServer()
{
Server server = GetCurrentServer();
return GetQRCode(server);
return GetServerURL(server);
}
public static string GetQRCode(Server server)
public static string GetServerURL(Server server)
{
string tag = string.Empty;
string parts = $"{server.method}:{server.password}@{server.server}:{server.server_port}";
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts));
if(!server.remarks.IsNullOrEmpty())
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,
HttpUtility.UrlEncode(server.server, Encoding.UTF8),
server.server_port,
HttpUtility.UrlEncode(pluginPart, Encoding.UTF8));
}
if (!server.remarks.IsNullOrEmpty())
{
tag = $"#{HttpUtility.UrlEncode(server.remarks, Encoding.UTF8)}";
}
return $"ss://{base64}{tag}";
return $"ss://{url}{tag}";
}
public void UpdatePACFromGFWList()
@@ -423,6 +490,8 @@ namespace Shadowsocks.Controller
protected void Reload()
{
StopPlugins();
Encryption.RNG.Reload();
// some logic in configuration updated the config when saving, we need to read it again
_config = Configuration.Load();
@@ -465,6 +534,7 @@ namespace Shadowsocks.Controller
strategy.ReloadServers();
}
StartPlugins();
privoxyRunner.Start(_config);
TCPRelay tcpRelay = new TCPRelay(this, _config);
@@ -502,6 +572,15 @@ namespace Shadowsocks.Controller
Utils.ReleaseMemory(true);
}
private void StartPlugins()
{
foreach (var server in _config.configs)
{
// Early start plugin processes
GetPluginLocalEndPointIfConfigured(server);
}
}
protected void SaveConfig(Configuration newConfig)
{
Configuration.Save(newConfig);
@@ -510,20 +589,7 @@ namespace Shadowsocks.Controller
private void UpdateSystemProxy()
{
if (_config.enabled)
{
SystemProxy.Update(_config, false, _pacServer);
_systemProxyIsDirty = true;
}
else
{
// only switch it off if we have switched it on
if (_systemProxyIsDirty)
{
SystemProxy.Update(_config, false, _pacServer);
_systemProxyIsDirty = false;
}
}
SystemProxy.Update(_config, false, _pacServer);
}
private void pacServer_PACFileChanged(object sender, EventArgs e)
@@ -552,7 +618,7 @@ namespace Shadowsocks.Controller
UpdatePACFromGFWList();
return;
}
List<string> lines = GFWListUpdater.ParseResult(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt")));
List<string> lines = new List<string>();
if (File.Exists(PACServer.USER_RULE_FILE))
{
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
@@ -566,6 +632,7 @@ namespace Shadowsocks.Controller
}
}
}
lines.AddRange(GFWListUpdater.ParseResult(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt"))));
string abpContent;
if (File.Exists(PACServer.USER_ABP_FILE))
{
+88 -84
View File
@@ -4,40 +4,40 @@ Shadowsocks=Shadowsocks
# Menu items
Enable System Proxy=システムの代理を有効にする
Enable System Proxy=システム プロキシを有効にする
Mode=モード
PAC=PAC
Global=全般
Servers=サーバ
Edit Servers...=サーバーを編集する...
Servers=サーバー
Edit Servers...=サーバーの編集...
Statistics Config...=統計情報の設定...
Start on Boot=システムと同時に起動
Forward Proxy...=代理を転送する...
Allow Clients from LAN=LANからのクライアントを許可する
Forward Proxy...=フォワードプロキシの設定...
Allow Clients from LAN=LAN からのアクセスを許可
Local PAC=ローカル PAC
Online PAC=オンライン PAC
Edit Local PAC File...=ローカル PAC ファイルを編集する...
Update Local PAC from GFWList=GFWList から、ローカル PACを更新する
Edit User Rule for GFWList...=利用者規則を編集する...
Secure Local PAC=安全なローカル PAC
Copy Local PAC URL=ローカルのPAC URLをコピー
Share Server Config...=サーバーの設定を共有する...
Scan QRCode from Screen...=画面からの QRコードをスキャン...
Import URL from Clipboard...=クリップボードからの URLを貼り付け...
Edit Local PAC File...=ローカル PAC ファイルの編集...
Update Local PAC from GFWList=GFWList からローカル PAC を更新
Edit User Rule for GFWList...=ユーザールールの編集...
Secure Local PAC=ローカル PAC を保護
Copy Local PAC URL=ローカル PAC URL をコピー
Share Server Config...=サーバーの設定を共有...
Scan QRCode from Screen...=画面から QR コードをスキャン...
Import URL from Clipboard...=クリップボードから URL をインポート...
Availability Statistics=可用性の統計
Show Logs...=ログを表示する...
Verbose Logging=詳細なログ
Show Logs...=ログの表示...
Verbose Logging=詳細なログを記録
Updates...=更新...
Check for Updates...=更新プログラムを確認しています...
Check for Updates at Startup=起動と同時に更新プログラムを確認しています
Check Pre-release Version=先行開発版の更新を確認しています...
Edit Hotkeys...=ホットキーを編集する...
About...=について...
Check for Updates...=更新プログラムの確認...
Check for Updates at Startup=起動時に更新プログラムを確認
Check Pre-release Version=先行開発版も確認
Edit Hotkeys...=ホットキーの編集...
About...=Shadowsocks について...
Help=ヘルプ
Quit=終了
Edit Servers=サーバを編集する
Load Balance=バランス
High Availability=高パフォーマンス
Edit Servers=サーバーの編集
Load Balance=負荷分散
High Availability=高可用性
Choose by statistics=統計で選ぶ
# Config Form
@@ -45,42 +45,46 @@ Choose by statistics=統計で選ぶ
&Add=新規 (&A)
&Delete=削除 (&D)
Dupli&cate=コピー (&C)
Server=サーバ
Server=サーバー
Server Addr=サーバーアドレス
Server Port=サーバポート
Password=暗証番号
Server Port=サーバーポート
Password=パスワード
Show Password=パスワードを表示する
Encryption=暗号化
Proxy Port=代理ポート
Remarks=短評する
Plugin=プラグイン
Plugin Options=プラグインのオプション
Proxy Port=プロキシポート
Remarks=付記
Timeout(Sec)=タイムアウト (秒)
OK=はい
Cancel=いいえ
New server=新規サーバ
OK=OK
Cancel=キャンセル
New server=新規サーバー
Move &Up=上に移動 (&U)
Move D&own=下に移動 (&O)
# Proxy Form
Edit Proxy=代理を編集する
Use Proxy=代理を利用する
Proxy Type=代理類型
Proxy Addr=代理アドレス
Proxy Port=代理ポート
Edit Proxy=プロキシの編集
Use Proxy=プロキシを利用する
Proxy Type=プロキシの種類
Proxy Addr=プロキシアドレス
Proxy Port=プロキシポート
If server has a plugin, proxy will not be used=サーバーにプラグインがある場合、プロキシは利用されません
# Log Form
&File=ファイル (&F)
&Open Location=この場所を開く (&O)
&Open Location=ファイルの場所を開く (&O)
E&xit=終了 (&X)
&View=ビュー (&V)
&Clean Logs=ログを削除する (&C)
Change &Font=フォントを変更する (&F)
&Wrap Text=文字改行 (&W)
&Top Most=一番上 (&T)
&Show Toolbar=ツールバーを表示する (&S)
&View=表示 (&V)
&Clean Logs=ログの削除 (&C)
Change &Font=フォント (&F)
&Wrap Text=右端で折り返す (&W)
&Top Most=常に最前面に表示 (&T)
&Show Toolbar=ツールバーの表示 (&S)
Log Viewer=ログビューア
Inbound=輸入
Outbound=輸出
Inbound=受信
Outbound=送信
# QRCode Form
@@ -88,16 +92,16 @@ QRCode and URL=QR コードと URL
# PAC Url Form
Edit Online PAC URL=オンライン PAC URLを編集する
Edit Online PAC URL...=オンライン PAC URLを編集する...
Edit Online PAC URL=オンライン PAC URL の編集
Edit Online PAC URL...=オンライン PAC URL の編集...
Please input PAC Url=PAC URLを入力して下さい
# HotkeySettings Form
Switch system proxy=代理を切換える
Switch system proxy mode=代理モードを切換える
Switch share over LAN=LAN経由でシェアを切換える
Show Logs=ログを表示する
Switch system proxy=システム プロキシの状態を切り替える
Switch system proxy mode=プロキシモードを切り替える
Switch share over LAN=LAN からのアクセスの許可を切り替える
Show Logs=ログの表示
Switch to prev server=前のサーバーに切り替える
Switch to next server=次のサーバーに切り替える
Reg All=全部登録する
@@ -105,38 +109,38 @@ Reg All=全部登録する
# Messages
Shadowsocks Error: {0}=Shadowsocks エラー: {0}
Port already in use=既に使用中のポート
Invalid server address=違法なサーバアドレス
Illegal port number format=不法なポート番号形式
Illegal timeout format=不法なタイムアウト形式
Please add at least one server=少なくとも一つのサーバーを追加して下さい
Server IP can not be blank=サーバ IP は空欄にできない
Password can not be blank=暗証番号は空欄にできない
Port out of range=ポートが範囲外
Port can't be 8123=ポート8123できない
Shadowsocks {0} Update Found=Shadowsocks {0} 更新プログラムを利用できます
No update is available=お使いのソフトウェアは最新です
Click here to update=プログラムの更新
Shadowsocks is here=Shadowsocks 此処です
You can turn on/off Shadowsocks in the context menu=コンテキストメニューにshadowsocksを有効化または無効化
System Proxy Enabled=システム 代理を有効にする
System Proxy Disabled=システム 代理を無効にする
Failed to update PAC file =PAC の更新に失敗しました
PAC updated=PAC の更新に正しくインストールされました
No updates found. Please report to GFWList if you have problems with it.=お使いのソフトウェアは最新です。もし貴方は問題がある、GFWListに報告して下さい。
No QRCode found. Try to zoom in or move it to the center of the screen.=QR コードを探し当てていません。ズームインまたはそれが画面の中心に移動して下さい。
Shadowsocks is already running.=Shadowsocks 実行中。
Find Shadowsocks icon in your notify tray.=shadowsocks通知トレイにアイコンを見つけて下さい。
If you want to start multiple Shadowsocks, make a copy in another directory.=同時に起動したい場合は、別のディレクトリにコピーしてもいいと思ってます。
Failed to decode QRCode=QR コードの復号化に失敗しました
Failed to update registry=登錄の更新に失敗しました
System Proxy On: =システム代理をオンにする:
Port already in use=ポートは既に使用されています。
Invalid server address=サーバーアドレスが無効です。
Illegal port number format=ポート番号のフォーマットが無効です。
Illegal timeout format=タイムアウト値のフォーマットが無効です。
Please add at least one server=少なくとも一つのサーバーを指定して下さい。
Server IP can not be blank=サーバー IP が指定されていません。
Password can not be blank=パスワードが指定されていません。
Port out of range=ポート番号は範囲外です。
Port can't be 8123=8123 番以外のポート番号を指定して下さい。
Shadowsocks {0} Update Found=Shadowsocks バージョン {0} は利用できます。
No update is available=お使いのバージョンは最新です。
Click here to update=クリックしてアップデートします。
Shadowsocks is here=Shadowsocks はここです。
You can turn on/off Shadowsocks in the context menu=コンテキストメニューを使って、Shadowsocks を有効または無効にすることができます。
System Proxy Enabled=システム プロキシが有効です。
System Proxy Disabled=システム プロキシが無効です。
Failed to update PAC file =PAC の更新に失敗しました。
PAC updated=PAC を更新しました。
No updates found. Please report to GFWList if you have problems with it.=お使いのバージョンは最新です。問題がある場合は、GFWList に報告して下さい。
No QRCode found. Try to zoom in or move it to the center of the screen.=QR コードが見つかりませんでした。コードを大きくするか、画面の中央に移動して下さい。
Shadowsocks is already running.=Shadowsocks 実行中
Find Shadowsocks icon in your notify tray.=通知領域には Shadowsocks のアイコンがあります。
If you want to start multiple Shadowsocks, make a copy in another directory.=複数起動したい場合は、プログラムファイルを別のフォルダーにコピーしてから、もう一度実行して下さい。
Failed to decode QRCode=QR コードの読み取りに失敗しました。
Failed to update registry=レジストリの更新に失敗しました。
System Proxy On: =システム プロキシが有効:
Running: Port {0}=実行中:ポート {0}
Unexpected error, shadowsocks will exit. Please report to=予想外のエラー、Shadowsocks を終了する。この場所を報告して下さい。
Unsupported operating system, use Windows Vista at least.=サポートしていないのOS、Windows Vista 以降のOSを利用して下さい。
Unsupported .NET Framework, please update to 4.6.2 or later.=サポートしていないの .NET Framework、4.6.2 以降のバンジョーを利用して下さい。
Proxy request failed=代理要求が失敗した。
Proxy handshake failed=代理の握手に失敗しました
Register hotkey failed=ホットキーの登錄に失敗しました
Unexpected error, shadowsocks will exit. Please report to=予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:
Unsupported operating system, use Windows Vista at least.=お使いの OS はサポートされていません。Windows Vista 以降の OS で実行して下さい。
Unsupported .NET Framework, please update to 4.6.2 or later.=お使いの .NET Framework はサポートされていません。4.6.2 以降のバンジョーをインストールして下さい。
Proxy request failed=プロキシ要求が失敗しました。
Proxy handshake failed=プロキシ ハンドシェイクに失敗しました。
Register hotkey failed=ホットキーの登錄に失敗しました。
Cannot parse hotkey: {0}=ホットキーを解析できません: {0}
Timeout is invalid, it should not exceed {0}=タイムアウトが無効であるか、それを超えてはならない {0}
Timeout is invalid, it should not exceed {0}=タイムアウト値が無効です。{0} 以下の値を指定して下さい。
Binary file not shown.
+4
View File
@@ -49,7 +49,10 @@ Server=服务器
Server Addr=服务器地址
Server Port=服务器端口
Password=密码
Show Password=显示密码
Encryption=加密
Plugin=插件
Plugin Options=插件选项
Proxy Port=代理端口
Remarks=备注
Timeout(Sec)=超时(秒)
@@ -66,6 +69,7 @@ Use Proxy=使用代理
Proxy Type=代理类型
Proxy Addr=代理地址
Proxy Port=代理端口
If server has a plugin, proxy will not be used=若服务器含有插件,代理将不被使用
# Log Form
+4
View File
@@ -49,7 +49,10 @@ Server=伺服器
Server Addr=伺服器位址
Server Port=伺服器連接埠
Password=密碼
Show Password=顯示密碼
Encryption=加密
Plugin=插件
Plugin Options=插件選項
Proxy Port=Proxy 連接埠
Remarks=註解
Timeout(Sec)=逾時 (秒)
@@ -66,6 +69,7 @@ Use Proxy=使用 Proxy
Proxy Type=Proxy 類型
Proxy Addr=Proxy 位址
Proxy Port=Proxy 連接埠
If server has a plugin, proxy will not be used=若伺服器含有插件,Proxy 將不被使用
# Log Form
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;
using Cyotek.Collections.Generic;
using Shadowsocks.Encryption.CircularBuffer;
using Shadowsocks.Controller;
using Shadowsocks.Encryption.Exception;
using Shadowsocks.Encryption.Stream;
@@ -21,8 +21,8 @@ namespace Shadowsocks.Encryption.AEAD
protected static byte[] _udpTmpBuf = new byte[65536];
// every connection should create its own buffer
private CircularBuffer<byte> _encCircularBuffer = new CircularBuffer<byte>(MAX_INPUT_SIZE * 2, false);
private CircularBuffer<byte> _decCircularBuffer = new CircularBuffer<byte>(MAX_INPUT_SIZE * 2, false);
private ByteCircularBuffer _encCircularBuffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
private ByteCircularBuffer _decCircularBuffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
public const int CHUNK_LEN_BYTES = 2;
public const uint CHUNK_LEN_MASK = 0x3FFFu;
@@ -88,15 +88,15 @@ namespace Shadowsocks.Encryption.AEAD
byte[] passbuf = Encoding.UTF8.GetBytes(password);
// init master key
if (_Masterkey == null) _Masterkey = new byte[keyLen];
if (_Masterkey.Length < keyLen) Array.Resize(ref _Masterkey, keyLen);
DeriveKey(passbuf, _Masterkey);
if (_Masterkey.Length != keyLen) Array.Resize(ref _Masterkey, keyLen);
DeriveKey(passbuf, _Masterkey, keyLen);
// init session key
if (_sessionKey == null) _sessionKey = new byte[keyLen];
}
public void DeriveKey(byte[] password, byte[] key)
public void DeriveKey(byte[] password, byte[] key, int keylen)
{
StreamEncryptor.LegacyDeriveKey(password, key);
StreamEncryptor.LegacyDeriveKey(password, key, keylen);
}
public void DeriveSessionKey(byte[] salt, byte[] masterKey, byte[] sessionKey)
@@ -254,7 +254,7 @@ namespace Shadowsocks.Encryption.AEAD
// we have enough data to decrypt one chunk
// drop chunk len and its tag from buffer
_decCircularBuffer.Get(CHUNK_LEN_BYTES + tagLen);
_decCircularBuffer.Skip(CHUNK_LEN_BYTES + tagLen);
byte[] encChunkBytes = _decCircularBuffer.Get(chunkLen + tagLen);
byte[] decChunkBytes = new byte[chunkLen];
uint decChunkLen = 0;
@@ -10,6 +10,7 @@ namespace Shadowsocks.Encryption.AEAD
: AEADEncryptor, IDisposable
{
private const int CIPHER_CHACHA20IETFPOLY1305 = 1;
private const int CIPHER_AES256GCM = 2;
private byte[] _sodiumEncSubkey;
private byte[] _sodiumDecSubkey;
@@ -24,6 +25,7 @@ namespace Shadowsocks.Encryption.AEAD
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)},
{"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)},
};
public static List<string> SupportedCiphers()
@@ -63,6 +65,13 @@ namespace Shadowsocks.Encryption.AEAD
null, _encNonce,
_sodiumEncSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_encrypt(ciphertext, ref encClen,
plaintext, (ulong)plen,
null, 0,
null, _encNonce,
_sodiumEncSubkey);
break;
default:
throw new System.Exception("not implemented");
}
@@ -91,6 +100,13 @@ namespace Shadowsocks.Encryption.AEAD
null, 0,
_decNonce, _sodiumDecSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_decrypt(plaintext, ref decPlen,
null,
ciphertext, (ulong)clen,
null, 0,
_decNonce, _sodiumDecSubkey);
break;
default:
throw new System.Exception("not implemented");
}
@@ -0,0 +1,510 @@
#region Original License
//New BSD License(BSD)
//
//Copyright(c) 2014-2015 Cyotek Ltd
//Copyright(c) 2012, Alex Regueiro
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Cyotek nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
//DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
namespace Shadowsocks.Encryption.CircularBuffer
{
/// <summary>
/// Represents a first-in, first-out collection of objects using a fixed buffer.
/// </summary>
/// <remarks>
/// <para>The capacity of a <see cref="ByteCircularBuffer" /> is the number of elements the <see cref="ByteCircularBuffer"/> can hold. </para>
/// <para>ByteCircularBuffer accepts <c>null</c> as a valid value for reference types and allows duplicate elements.</para>
/// <para>The <see cref="Get()"/> methods will remove the items that are returned from the ByteCircularBuffer. To view the contents of the ByteCircularBuffer without removing items, use the <see cref="Peek()"/> or <see cref="PeekLast"/> methods.</para>
/// </remarks>
public class ByteCircularBuffer
{
// based on http://circularbuffer.codeplex.com/
// http://en.wikipedia.org/wiki/Circular_buffer
// modified from https://github.com/cyotek/Cyotek.Collections.Generic.CircularBuffer
// some code taken from https://github.com/xorxornop/RingBuffer
// and https://github.com/xorxornop/PerfCopy
#region Instance Fields
private byte[] _buffer;
private int _capacity;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ByteCircularBuffer"/> class that is empty and has the specified initial capacity.
/// </summary>
/// <param name="capacity">The maximum capcity of the buffer.</param>
/// <exception cref="System.ArgumentException">Thown if the <paramref name="capacity"/> is less than zero.</exception>
public ByteCircularBuffer(int capacity)
{
if (capacity < 0)
{
throw new ArgumentException("The buffer capacity must be greater than or equal to zero.",
nameof(capacity));
}
_buffer = new byte[capacity];
this.Capacity = capacity;
this.Size = 0;
this.Head = 0;
this.Tail = 0;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the total number of elements the internal data structure can hold.
/// </summary>
/// <value>The total number of elements that the <see cref="ByteCircularBuffer"/> can contain.</value>
/// <exception cref="System.ArgumentOutOfRangeException">Thrown if the specified new capacity is smaller than the current contents of the buffer.</exception>
public int Capacity
{
get { return _capacity; }
set
{
if (value != _capacity)
{
if (value < this.Size)
{
throw new ArgumentOutOfRangeException(nameof(value), value,
"The new capacity must be greater than or equal to the buffer size.");
}
var newBuffer = new byte[value];
if (this.Size > 0)
{
this.CopyTo(newBuffer);
}
_buffer = newBuffer;
_capacity = value;
}
}
}
/// <summary>
/// Gets the index of the beginning of the buffer data.
/// </summary>
/// <value>The index of the first element in the buffer.</value>
public int Head { get; protected set; }
/// <summary>
/// Gets a value indicating whether the buffer is empty.
/// </summary>
/// <value><c>true</c> if buffer is empty; otherwise, <c>false</c>.</value>
public virtual bool IsEmpty => this.Size == 0;
/// <summary>
/// Gets a value indicating whether the buffer is full.
/// </summary>
/// <value><c>true</c> if the buffer is full; otherwise, <c>false</c>.</value>
/// <remarks>The <see cref="IsFull"/> property always returns <c>false</c> if the <see cref="AllowOverwrite"/> property is set to <c>true</c>.</remarks>
public virtual bool IsFull => this.Size == this.Capacity;
/// <summary>
/// Gets the number of elements contained in the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <value>The number of elements contained in the <see cref="ByteCircularBuffer"/>.</value>
public int Size { get; protected set; }
/// <summary>
/// Gets the index of the end of the buffer data.
/// </summary>
/// <value>The index of the last element in the buffer.</value>
public int Tail { get; protected set; }
#endregion
#region Public Members
/// <summary>
/// Removes all items from the <see cref="ByteCircularBuffer" />.
/// </summary>
public void Clear()
{
this.Size = 0;
this.Head = 0;
this.Tail = 0;
_buffer = new byte[this.Capacity];
}
/// <summary>
/// Determines whether the <see cref="ByteCircularBuffer" /> contains a specific value.
/// </summary>
/// <param name="item">The object to locate in the <see cref="ByteCircularBuffer" />.</param>
/// <returns><c>true</c> if <paramref name="item" /> is found in the <see cref="ByteCircularBuffer" />; otherwise, <c>false</c>.</returns>
public bool Contains(byte item)
{
var bufferIndex = this.Head;
var comparer = EqualityComparer<byte>.Default;
var result = false;
for (int i = 0; i < this.Size; i++, bufferIndex++)
{
if (bufferIndex == this.Capacity)
{
bufferIndex = 0;
}
if (comparer.Equals(_buffer[bufferIndex], item))
{
result = true;
break;
}
}
return result;
}
/// <summary>
/// Copies the entire <see cref="ByteCircularBuffer"/> to a compatible one-dimensional array, starting at the beginning of the target array.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
public void CopyTo(byte[] array)
{
this.CopyTo(array, 0);
}
/// <summary>
/// Copies the entire <see cref="ByteCircularBuffer"/> to a compatible one-dimensional array, starting at the specified index of the target array.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
public void CopyTo(byte[] array, int arrayIndex)
{
this.CopyTo(this.Head, array, arrayIndex, Math.Min(this.Size, array.Length - arrayIndex));
}
/// <summary>
/// Copies a range of elements from the <see cref="ByteCircularBuffer"/> to a compatible one-dimensional array, starting at the specified index of the target array.
/// </summary>
/// <param name="index">The zero-based index in the source <see cref="ByteCircularBuffer"/> at which copying begins.</param>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
/// <param name="count">The number of elements to copy.</param>
public virtual void CopyTo(int index, byte[] array, int arrayIndex, int count)
{
if (count > this.Size)
{
throw new ArgumentOutOfRangeException(nameof(count), count,
"The read count cannot be greater than the buffer size.");
}
var startAnchor = index;
var dstIndex = arrayIndex;
while (count > 0)
{
int chunk = Math.Min(Capacity - startAnchor, count);
Buffer.BlockCopy(_buffer, startAnchor, array, dstIndex, chunk);
startAnchor = (startAnchor + chunk == Capacity) ? 0 : startAnchor + chunk;
dstIndex += chunk;
count -= chunk;
}
}
/// <summary>
/// Removes and returns the specified number of objects from the beginning of the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="count">The number of elements to remove and return from the <see cref="ByteCircularBuffer"/>.</param>
/// <returns>The objects that are removed from the beginning of the <see cref="ByteCircularBuffer"/>.</returns>
public byte[] Get(int count)
{
if (count <= 0) throw new ArgumentOutOfRangeException("should greater than 0");
var result = new byte[count];
this.Get(result);
return result;
}
/// <summary>
/// Copies and removes the specified number elements from the <see cref="ByteCircularBuffer"/> to a compatible one-dimensional array, starting at the beginning of the target array.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <returns>The actual number of elements copied into <paramref name="array"/>.</returns>
public int Get(byte[] array)
{
if (array.Length <= 0) throw new ArgumentOutOfRangeException("should greater than 0");
return this.Get(array, 0, array.Length);
}
/// <summary>
/// Copies and removes the specified number elements from the <see cref="ByteCircularBuffer"/> to a compatible one-dimensional array, starting at the specified index of the target array.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
/// <param name="count">The number of elements to copy.</param>
/// <returns>The actual number of elements copied into <paramref name="array"/>.</returns>
public virtual int Get(byte[] array, int arrayIndex, int count)
{
if (arrayIndex < 0)
{
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Negative offset specified. Offsets must be positive.");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Negative count specified. Count must be positive.");
}
if (count > this.Size)
{
throw new ArgumentException("Ringbuffer contents insufficient for take/read operation.", nameof(count));
}
if (array.Length < arrayIndex + count)
{
throw new ArgumentException("Destination array too small for requested output.");
}
var bytesCopied = 0;
var dstIndex = arrayIndex;
while (count > 0)
{
int chunk = Math.Min(Capacity - this.Head, count);
Buffer.BlockCopy(_buffer, this.Head, array, dstIndex, chunk);
this.Head = (this.Head + chunk == Capacity) ? 0 : this.Head + chunk;
this.Size -= chunk;
dstIndex += chunk;
bytesCopied += chunk;
count -= chunk;
}
return bytesCopied;
}
/// <summary>
/// Removes and returns the object at the beginning of the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <returns>The object that is removed from the beginning of the <see cref="ByteCircularBuffer"/>.</returns>
/// <exception cref="System.InvalidOperationException">Thrown if the buffer is empty.</exception>
/// <remarks>This method is similar to the <see cref="Peek()"/> method, but <c>Peek</c> does not modify the <see cref="ByteCircularBuffer"/>.</remarks>
public virtual byte Get()
{
if (this.IsEmpty)
{
throw new InvalidOperationException("The buffer is empty.");
}
var item = _buffer[this.Head];
if (++this.Head == this.Capacity)
{
this.Head = 0;
}
this.Size--;
return item;
}
/// <summary>
/// Returns the object at the beginning of the <see cref="ByteCircularBuffer"/> without removing it.
/// </summary>
/// <returns>The object at the beginning of the <see cref="ByteCircularBuffer"/>.</returns>
/// <exception cref="System.InvalidOperationException">Thrown if the buffer is empty.</exception>
public virtual byte Peek()
{
if (this.IsEmpty)
{
throw new InvalidOperationException("The buffer is empty.");
}
var item = _buffer[this.Head];
return item;
}
/// <summary>
/// Returns the specified number of objects from the beginning of the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="count">The number of elements to return from the <see cref="ByteCircularBuffer"/>.</param>
/// <returns>The objects that from the beginning of the <see cref="ByteCircularBuffer"/>.</returns>
/// <exception cref="System.InvalidOperationException">Thrown if the buffer is empty.</exception>
public virtual byte[] Peek(int count)
{
if (this.IsEmpty)
{
throw new InvalidOperationException("The buffer is empty.");
}
var items = new byte[count];
this.CopyTo(items);
return items;
}
/// <summary>
/// Returns the object at the end of the <see cref="ByteCircularBuffer"/> without removing it.
/// </summary>
/// <returns>The object at the end of the <see cref="ByteCircularBuffer"/>.</returns>
/// <exception cref="System.InvalidOperationException">Thrown if the buffer is empty.</exception>
public virtual byte PeekLast()
{
int bufferIndex;
if (this.IsEmpty)
{
throw new InvalidOperationException("The buffer is empty.");
}
if (this.Tail == 0)
{
bufferIndex = this.Size - 1;
}
else
{
bufferIndex = this.Tail - 1;
}
var item = _buffer[bufferIndex];
return item;
}
/// <summary>
/// Copies an entire compatible one-dimensional array to the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the source of the elements copied to <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <exception cref="System.InvalidOperationException">Thrown if buffer does not have sufficient capacity to put in new items.</exception>
/// <remarks>If <see cref="Size"/> plus the size of <paramref name="array"/> exceeds the capacity of the <see cref="ByteCircularBuffer"/> and the <see cref="AllowOverwrite"/> property is <c>true</c>, the oldest items in the <see cref="ByteCircularBuffer"/> are overwritten with <paramref name="array"/>.</remarks>
public int Put(byte[] array)
{
return this.Put(array, 0, array.Length);
}
/// <summary>
/// Copies a range of elements from a compatible one-dimensional array to the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="array">The one-dimensional <see cref="Array"/> that is the source of the elements copied to <see cref="ByteCircularBuffer"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
/// <param name="count">The number of elements to copy.</param>
/// <exception cref="System.InvalidOperationException">Thrown if buffer does not have sufficient capacity to put in new items.</exception>
/// <remarks>If <see cref="Size"/> plus <paramref name="count"/> exceeds the capacity of the <see cref="ByteCircularBuffer"/> and the <see cref="AllowOverwrite"/> property is <c>true</c>, the oldest items in the <see cref="ByteCircularBuffer"/> are overwritten with <paramref name="array"/>.</remarks>
public virtual int Put(byte[] array, int arrayIndex, int count)
{
if (count <= 0) throw new ArgumentOutOfRangeException(nameof(count), "Count must be positive.");
if (this.Size + count > this.Capacity)
{
throw new InvalidOperationException("The buffer does not have sufficient capacity to put new items.");
}
if (array.Length < arrayIndex + count)
{
throw new ArgumentException("Source array too small for requested input.");
}
var srcIndex = arrayIndex;
var bytesToProcess = count;
while (bytesToProcess > 0)
{
int chunk = Math.Min(Capacity - Tail, bytesToProcess);
Buffer.BlockCopy(array, srcIndex, _buffer, Tail, chunk);
Tail = (Tail + chunk == Capacity) ? 0 : Tail + chunk;
this.Size += chunk;
srcIndex += chunk;
bytesToProcess -= chunk;
}
return count;
}
/// <summary>
/// Adds a byte to the end of the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="item">The byte to add to the <see cref="ByteCircularBuffer"/>. </param>
/// <exception cref="System.InvalidOperationException">Thrown if buffer does not have sufficient capacity to put in new items.</exception>
public virtual void Put(byte item)
{
if (IsFull)
{
throw new InvalidOperationException("The buffer does not have sufficient capacity to put new items.");
}
_buffer[this.Tail] = item;
this.Tail++;
if (this.Size == this.Capacity)
{
this.Head++;
if (this.Head >= this.Capacity)
{
this.Head -= this.Capacity;
}
}
if (this.Tail == this.Capacity)
{
this.Tail = 0;
}
if (this.Size != this.Capacity)
{
this.Size++;
}
}
/// <summary>
/// Increments the starting index of the data buffer in the <see cref="ByteCircularBuffer"/>.
/// </summary>
/// <param name="count">The number of elements to increment the data buffer start index by.</param>
public void Skip(int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Negative count specified. Count must be positive.");
}
if (count > this.Size)
{
throw new ArgumentException("Ringbuffer contents insufficient for operation.", nameof(count));
}
// Modular division gives new offset position
this.Head = (this.Head + count) % Capacity;
this.Size -= count;
}
/// <summary>
/// Copies the <see cref="ByteCircularBuffer"/> elements to a new array.
/// </summary>
/// <returns>A new array containing elements copied from the <see cref="ByteCircularBuffer"/>.</returns>
/// <remarks>The <see cref="ByteCircularBuffer"/> is not modified. The order of the elements in the new array is the same as the order of the elements from the beginning of the <see cref="ByteCircularBuffer"/> to its end.</remarks>
public byte[] ToArray()
{
var result = new byte[this.Size];
this.CopyTo(result);
return result;
}
#endregion
}
}
@@ -71,6 +71,8 @@
public const int ATYP_DOMAIN = 0x03;
public const int ATYP_IPv6 = 0x04;
public const int MD5_LEN = 16;
protected EncryptorBase(string method, string password)
{
Method = method;
@@ -14,6 +14,18 @@ namespace Shadowsocks.Encryption
static EncryptorFactory()
{
var AEADMbedTLSEncryptorSupportedCiphers = AEADMbedTLSEncryptor.SupportedCiphers();
var AEADSodiumEncryptorSupportedCiphers = AEADSodiumEncryptor.SupportedCiphers();
if (Sodium.AES256GCMAvailable)
{
// prefer to aes-256-gcm in libsodium
AEADMbedTLSEncryptorSupportedCiphers.Remove("aes-256-gcm");
}
else
{
AEADSodiumEncryptorSupportedCiphers.Remove("aes-256-gcm");
}
foreach (string method in StreamMbedTLSEncryptor.SupportedCiphers())
{
_registeredEncryptors.Add(method, typeof(StreamMbedTLSEncryptor));
@@ -22,11 +34,11 @@ namespace Shadowsocks.Encryption
{
_registeredEncryptors.Add(method, typeof(StreamSodiumEncryptor));
}
foreach (string method in AEADMbedTLSEncryptor.SupportedCiphers())
foreach (string method in AEADMbedTLSEncryptorSupportedCiphers)
{
_registeredEncryptors.Add(method, typeof(AEADMbedTLSEncryptor));
}
foreach (string method in AEADSodiumEncryptor.SupportedCiphers())
foreach (string method in AEADSodiumEncryptorSupportedCiphers)
{
_registeredEncryptors.Add(method, typeof(AEADSodiumEncryptor));
}
+16
View File
@@ -14,6 +14,8 @@ namespace Shadowsocks.Encryption
private static bool _initialized = false;
private static readonly object _initLock = new object();
public static bool AES256GCMAvailable { get; private set; } = false;
static Sodium()
{
string dllPath = Utils.GetTempPath(DLLNAME);
@@ -42,6 +44,9 @@ namespace Shadowsocks.Encryption
{
_initialized = true;
}
AES256GCMAvailable = crypto_aead_aes256gcm_is_available() == 1;
Logging.Debug($"sodium: AES256GCMAvailable is {AES256GCMAvailable}");
}
}
}
@@ -52,6 +57,9 @@ namespace Shadowsocks.Encryption
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int sodium_init();
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int crypto_aead_aes256gcm_is_available();
#region AEAD
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
@@ -65,6 +73,14 @@ namespace Shadowsocks.Encryption
public static extern int crypto_aead_chacha20poly1305_ietf_decrypt(byte[] m, ref ulong mlen_p,
byte[] nsec, byte[] c, ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_aes256gcm_encrypt(byte[] c, ref ulong clen_p, byte[] m, ulong mlen,
byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_aes256gcm_decrypt(byte[] m, ref ulong mlen_p, byte[] nsec, byte[] c,
ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
#endregion
#region Stream
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Cyotek.Collections.Generic;
using Shadowsocks.Encryption.CircularBuffer;
using Shadowsocks.Controller;
namespace Shadowsocks.Encryption.Stream
@@ -14,8 +14,8 @@ namespace Shadowsocks.Encryption.Stream
protected static byte[] _udpTmpBuf = new byte[65536];
// every connection should create its own buffer
private CircularBuffer<byte> _encCircularBuffer = new CircularBuffer<byte>(TCPHandler.BufferSize * 2, false);
private CircularBuffer<byte> _decCircularBuffer = new CircularBuffer<byte>(TCPHandler.BufferSize * 2, false);
private ByteCircularBuffer _encCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2);
private ByteCircularBuffer _decCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2);
protected Dictionary<string, EncryptorInfo> ciphers;
@@ -64,25 +64,25 @@ namespace Shadowsocks.Encryption.Stream
{
byte[] passbuf = Encoding.UTF8.GetBytes(password);
if (_key == null) _key = new byte[keyLen];
if (_key.Length < keyLen) Array.Resize(ref _key, keyLen);
LegacyDeriveKey(passbuf, _key);
if (_key.Length != keyLen) Array.Resize(ref _key, keyLen);
LegacyDeriveKey(passbuf, _key, keyLen);
}
public static void LegacyDeriveKey(byte[] password, byte[] key)
public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen)
{
byte[] result = new byte[password.Length + 16];
byte[] result = new byte[password.Length + MD5_LEN];
int i = 0;
byte[] md5sum = null;
while (i < key.Length) {
while (i < keylen) {
if (i == 0) {
md5sum = MbedTLS.MD5(password);
} else {
md5sum.CopyTo(result, 0);
password.CopyTo(result, md5sum.Length);
Array.Copy(md5sum, 0, result, 0, MD5_LEN);
Array.Copy(password, 0, result, MD5_LEN, password.Length);
md5sum = MbedTLS.MD5(result);
}
md5sum.CopyTo(key, i);
i += md5sum.Length;
Array.Copy(md5sum, 0, key, i, Math.Min(MD5_LEN, keylen - i));
i += MD5_LEN;
}
}
@@ -143,7 +143,8 @@ namespace Shadowsocks.Encryption.Stream
}
byte[] cipher = _decCircularBuffer.ToArray();
cipherUpdate(false, cipher.Length, cipher, outbuf);
_decCircularBuffer.Clear();
// move pointer only
_decCircularBuffer.Skip(_decCircularBuffer.Size);
outlength = cipher.Length;
// done the decryption
}
+3 -3
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<Caseless StringComparison="Ordinal"/>
<Costura/>
<Caseless StringComparison="Ordinal" />
<Costura />
</Weavers>
+4 -1
View File
@@ -89,7 +89,10 @@ namespace Shadowsocks.Model
configs = new List<Server>()
{
GetDefaultServer()
}
},
logViewer = new LogViewerConfig(),
proxy = new ProxyConfig(),
hotkey = new HotkeyConfig()
};
}
}
+108 -22
View File
@@ -1,18 +1,21 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Shadowsocks.Controller;
using System.Text.RegularExpressions;
namespace Shadowsocks.Model
{
[Serializable]
public class Server
{
#region ParseLegacyURL
public static readonly Regex
UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase),
DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
#endregion ParseLegacyURL
private const int DefaultServerTimeoutSec = 5;
public const int MaxServerTimeoutSec = 20;
@@ -21,6 +24,8 @@ namespace Shadowsocks.Model
public int server_port;
public string password;
public string method;
public string plugin;
public string plugin_opts;
public string remarks;
public int timeout;
@@ -65,35 +70,116 @@ namespace Shadowsocks.Model
server = "";
server_port = 8388;
method = "aes-256-cfb";
plugin = "";
plugin_opts = "";
password = "";
remarks = "";
timeout = DefaultServerTimeoutSec;
}
private static Server ParseLegacyURL(string ssURL)
{
var match = UrlFinder.Match(ssURL);
if (!match.Success)
return null;
Server server = new Server();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!tag.IsNullOrEmpty())
{
server.remarks = 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;
server.method = details.Groups["method"].Value;
server.password = details.Groups["password"].Value;
server.server = details.Groups["hostname"].Value;
server.server_port = int.Parse(details.Groups["port"].Value);
return server;
}
public static List<Server> GetServers(string ssURL)
{
var matches = UrlFinder.Matches(ssURL);
if (matches.Count <= 0) return null;
List<Server> servers = new List<Server>();
foreach (Match match in matches)
{
Server tmp = new Server();
var base64 = match.Groups["base64"].Value;
var tag = match.Groups["tag"].Value;
if (!tag.IsNullOrEmpty())
{
tmp.remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
}
Match details = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
if (!details.Success)
continue;
tmp.method = details.Groups["method"].Value;
tmp.password = details.Groups["password"].Value;
tmp.server = details.Groups["hostname"].Value;
tmp.server_port = int.Parse(details.Groups["port"].Value);
var serverUrls = ssURL.Split('\r', '\n');
servers.Add(tmp);
List<Server> servers = new List<Server>();
foreach (string serverUrl in serverUrls)
{
string _serverUrl = serverUrl.Trim();
if (!_serverUrl.BeginWith("ss://", StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
Server legacyServer = ParseLegacyURL(serverUrl);
if (legacyServer != null) //legacy
{
servers.Add(legacyServer);
}
else //SIP002
{
Uri parsedUrl;
try
{
parsedUrl = new Uri(serverUrl);
}
catch (UriFormatException)
{
continue;
}
Server server = new Server
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
server = parsedUrl.GetComponents(UriComponents.Host, UriFormat.Unescaped),
server_port = parsedUrl.Port,
};
// parse base64 UserInfo
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
string base64 = rawUserInfo.Replace('-', '+').Replace('_', '/'); // Web-safe base64 to normal base64
string userInfo = "";
try
{
userInfo = Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=')));
}
catch (FormatException)
{
continue;
}
string[] userInfoParts = userInfo.Split(new char[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
continue;
}
server.method = userInfoParts[0];
server.password = userInfoParts[1];
NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query);
string[] pluginParts = HttpUtility.UrlDecode(queryParameters["plugin"] ?? "").Split(new[] { ';' }, 2);
if (pluginParts.Length > 0)
{
server.plugin = pluginParts[0] ?? "";
}
if (pluginParts.Length > 1)
{
server.plugin_opts = pluginParts[1] ?? "";
}
servers.Add(server);
}
}
return servers;
}
@@ -0,0 +1,27 @@
using System;
namespace Shadowsocks.Model
{
/*
* Data come from WinINET
*/
[Serializable]
public class SysproxyConfig
{
public bool UserSettingsRecorded;
public string Flags;
public string ProxyServer;
public string BypassList;
public string PacUrl;
public SysproxyConfig()
{
UserSettingsRecorded = false;
Flags = "1";
ProxyServer = "";
BypassList = "";
PacUrl = "";
}
}
}
+13 -35
View File
@@ -122,11 +122,19 @@ namespace Shadowsocks
Logging.Info("os wake up");
if (MainController != null)
{
System.Timers.Timer timer = new System.Timers.Timer(10 * 1000);
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = false;
timer.Enabled = true;
timer.Start();
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Thread.Sleep(10 * 1000);
try
{
MainController.Start();
Logging.Info("controller started");
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
});
}
break;
case PowerModes.Suspend:
@@ -140,36 +148,6 @@ namespace Shadowsocks
}
}
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
if (MainController != null)
{
MainController.Start();
Logging.Info("controller started");
}
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
finally
{
try
{
System.Timers.Timer timer = (System.Timers.Timer)sender;
timer.Enabled = false;
timer.Stop();
timer.Dispose();
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
}
}
private static void Application_ApplicationExit(object sender, EventArgs e)
{
// detach static event handlers
@@ -42,7 +42,10 @@ namespace Shadowsocks.Util.Sockets
arg.Completed += OnTcpConnectCompleted;
arg.UserToken = new TcpUserToken(callback, state);
Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg);
if(!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg))
{
OnTcpConnectCompleted(this, arg);
}
}
private class FakeAsyncResult : IAsyncResult
+66 -31
View File
@@ -1,15 +1,19 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using Shadowsocks.Model;
using System.Text;
using Newtonsoft.Json;
namespace Shadowsocks.Util.SystemProxy
{
public static class Sysproxy
{
private static bool _userSettingsRecorded = false;
private const string _userWininetConfigFile = "user-wininet.json";
private static string _queryStr;
// In general, this won't change
// format:
@@ -17,7 +21,7 @@ namespace Shadowsocks.Util.SystemProxy
// <proxy-server><CR-LF>
// <bypass-list><CR-LF>
// <pac-url>
private static string[] _userSettings = new string[4];
private static SysproxyConfig _userSettings = null;
enum RET_ERRORS : int
{
@@ -31,8 +35,7 @@ namespace Shadowsocks.Util.SystemProxy
static Sysproxy()
{
try
{
try {
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
}
@@ -44,16 +47,16 @@ namespace Shadowsocks.Util.SystemProxy
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
{
string str;
if (_userSettingsRecorded == false)
Read();
if (!_userSettings.UserSettingsRecorded)
{
// record user settings
ExecSysproxy("query", out str);
ParseQueryStr(str);
_userSettingsRecorded = true;
ExecSysproxy("query");
ParseQueryStr(_queryStr);
}
string arguments;
string arguments;
if (enable)
{
arguments = global
@@ -63,20 +66,21 @@ namespace Shadowsocks.Util.SystemProxy
else
{
// restore user settings
var flags = _userSettings[0];
var proxy_server = _userSettings[1] ?? "-";
var bypass_list = _userSettings[2] ?? "-";
var pac_url = _userSettings[3] ?? "-";
var flags = _userSettings.Flags;
var proxy_server = _userSettings.ProxyServer ?? "-";
var bypass_list = _userSettings.BypassList ?? "-";
var pac_url = _userSettings.PacUrl ?? "-";
arguments = $"set {flags} {proxy_server} {bypass_list} {pac_url}";
// have to get new settings
_userSettingsRecorded = false;
_userSettings.UserSettingsRecorded = false;
}
ExecSysproxy(arguments, out str);
Save();
ExecSysproxy(arguments);
}
private static void ExecSysproxy(string arguments, out string queryStr)
private static void ExecSysproxy(string arguments)
{
using (var process = new Process())
{
@@ -107,24 +111,55 @@ namespace Shadowsocks.Util.SystemProxy
throw new ProxyException(stderr);
}
if (arguments == "query" && stdout.IsNullOrWhiteSpace())
{
// we cannot get user settings
throw new ProxyException("failed to query wininet settings");
if (arguments == "query") {
if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty()) {
// we cannot get user settings
throw new ProxyException("failed to query wininet settings");
}
_queryStr = stdout;
}
queryStr = stdout;
}
}
private static void Save()
{
try {
using (StreamWriter sw = new StreamWriter(File.Open(_userWininetConfigFile, FileMode.Create))) {
string jsonString = JsonConvert.SerializeObject(_userSettings, Formatting.Indented);
sw.Write(jsonString);
sw.Flush();
}
} catch (IOException e) {
Logging.LogUsefulException(e);
}
}
private static void Read()
{
try {
string configContent = File.ReadAllText(_userWininetConfigFile);
_userSettings = JsonConvert.DeserializeObject<SysproxyConfig>(configContent);
} catch(Exception) {
// Suppress all exceptions. finally block will initialize new user config settings.
} finally {
if (_userSettings == null) _userSettings = new SysproxyConfig();
}
}
private static void ParseQueryStr(string str)
{
_userSettings = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < 4; i++)
{
// handle output from WinINET
if (_userSettings[i] == "(null)")
_userSettings[i] = null;
}
string[] userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
_userSettings.Flags = userSettingsArr[0];
// handle output from WinINET
if (userSettingsArr[1] == "(null)") _userSettings.ProxyServer = null;
else _userSettings.ProxyServer = userSettingsArr[1];
if (userSettingsArr[2] == "(null)") _userSettings.BypassList = null;
else _userSettings.BypassList = userSettingsArr[2];
if (userSettingsArr[3] == "(null)") _userSettings.PacUrl = null;
else _userSettings.PacUrl = userSettingsArr[3];
_userSettings.UserSettingsRecorded = true;
}
}
}
}
+112 -39
View File
@@ -29,6 +29,8 @@
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.PluginOptionsLabel = new System.Windows.Forms.Label();
this.PluginTextBox = new System.Windows.Forms.TextBox();
this.RemarksTextBox = new System.Windows.Forms.TextBox();
this.RemarksLabel = new System.Windows.Forms.Label();
this.IPLabel = new System.Windows.Forms.Label();
@@ -41,6 +43,9 @@
this.EncryptionSelect = new System.Windows.Forms.ComboBox();
this.TimeoutLabel = new System.Windows.Forms.Label();
this.TimeoutTextBox = new System.Windows.Forms.TextBox();
this.PluginLabel = new System.Windows.Forms.Label();
this.PluginOptionsTextBox = new System.Windows.Forms.TextBox();
this.ShowPasswdCheckBox = new System.Windows.Forms.CheckBox();
this.panel2 = new System.Windows.Forms.Panel();
this.OKButton = new System.Windows.Forms.Button();
this.MyCancelButton = new System.Windows.Forms.Button();
@@ -74,23 +79,28 @@
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 5);
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsLabel, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.PluginTextBox, 1, 5);
this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 8);
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 8);
this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.PasswordTextBox, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 3);
this.tableLayoutPanel1.Controls.Add(this.TimeoutLabel, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.TimeoutTextBox, 1, 6);
this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 4);
this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 4);
this.tableLayoutPanel1.Controls.Add(this.TimeoutLabel, 0, 9);
this.tableLayoutPanel1.Controls.Add(this.TimeoutTextBox, 1, 9);
this.tableLayoutPanel1.Controls.Add(this.PluginLabel, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsTextBox, 1, 6);
this.tableLayoutPanel1.Controls.Add(this.ShowPasswdCheckBox, 1, 3);
this.tableLayoutPanel1.Location = new System.Drawing.Point(8, 21);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(3);
this.tableLayoutPanel1.RowCount = 7;
this.tableLayoutPanel1.RowCount = 10;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
@@ -98,24 +108,47 @@
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(255, 167);
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(267, 243);
this.tableLayoutPanel1.TabIndex = 0;
//
// PluginOptionsLabel
//
this.PluginOptionsLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PluginOptionsLabel.AutoSize = true;
this.PluginOptionsLabel.Location = new System.Drawing.Point(6, 166);
this.PluginOptionsLabel.Name = "PluginOptionsLabel";
this.PluginOptionsLabel.Size = new System.Drawing.Size(89, 12);
this.PluginOptionsLabel.TabIndex = 15;
this.PluginOptionsLabel.Text = "Plugin Options";
//
// PluginTextBox
//
this.PluginTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PluginTextBox.Location = new System.Drawing.Point(101, 135);
this.PluginTextBox.MaxLength = 256;
this.PluginTextBox.Name = "PluginTextBox";
this.PluginTextBox.Size = new System.Drawing.Size(160, 21);
this.PluginTextBox.TabIndex = 4;
this.PluginTextBox.WordWrap = false;
//
// RemarksTextBox
//
this.RemarksTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.RemarksTextBox.Location = new System.Drawing.Point(89, 113);
this.RemarksTextBox.Location = new System.Drawing.Point(101, 189);
this.RemarksTextBox.MaxLength = 32;
this.RemarksTextBox.Name = "RemarksTextBox";
this.RemarksTextBox.Size = new System.Drawing.Size(160, 21);
this.RemarksTextBox.TabIndex = 4;
this.RemarksTextBox.TabIndex = 6;
this.RemarksTextBox.WordWrap = false;
//
// RemarksLabel
//
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RemarksLabel.AutoSize = true;
this.RemarksLabel.Location = new System.Drawing.Point(36, 117);
this.RemarksLabel.Location = new System.Drawing.Point(48, 193);
this.RemarksLabel.Name = "RemarksLabel";
this.RemarksLabel.Size = new System.Drawing.Size(47, 12);
this.RemarksLabel.TabIndex = 9;
@@ -125,7 +158,7 @@
//
this.IPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.IPLabel.AutoSize = true;
this.IPLabel.Location = new System.Drawing.Point(24, 10);
this.IPLabel.Location = new System.Drawing.Point(36, 10);
this.IPLabel.Name = "IPLabel";
this.IPLabel.Size = new System.Drawing.Size(59, 12);
this.IPLabel.TabIndex = 0;
@@ -135,7 +168,7 @@
//
this.ServerPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ServerPortLabel.AutoSize = true;
this.ServerPortLabel.Location = new System.Drawing.Point(12, 37);
this.ServerPortLabel.Location = new System.Drawing.Point(24, 37);
this.ServerPortLabel.Name = "ServerPortLabel";
this.ServerPortLabel.Size = new System.Drawing.Size(71, 12);
this.ServerPortLabel.TabIndex = 1;
@@ -145,16 +178,17 @@
//
this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PasswordLabel.AutoSize = true;
this.PasswordLabel.Location = new System.Drawing.Point(30, 64);
this.PasswordLabel.Location = new System.Drawing.Point(42, 64);
this.PasswordLabel.Name = "PasswordLabel";
this.PasswordLabel.Size = new System.Drawing.Size(53, 12);
this.PasswordLabel.TabIndex = 2;
this.PasswordLabel.Text = "Password";
this.PasswordLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// IPTextBox
//
this.IPTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.IPTextBox.Location = new System.Drawing.Point(89, 6);
this.IPTextBox.Location = new System.Drawing.Point(101, 6);
this.IPTextBox.MaxLength = 512;
this.IPTextBox.Name = "IPTextBox";
this.IPTextBox.Size = new System.Drawing.Size(160, 21);
@@ -164,7 +198,7 @@
// ServerPortTextBox
//
this.ServerPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ServerPortTextBox.Location = new System.Drawing.Point(89, 33);
this.ServerPortTextBox.Location = new System.Drawing.Point(101, 33);
this.ServerPortTextBox.MaxLength = 10;
this.ServerPortTextBox.Name = "ServerPortTextBox";
this.ServerPortTextBox.Size = new System.Drawing.Size(160, 21);
@@ -174,7 +208,7 @@
// PasswordTextBox
//
this.PasswordTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PasswordTextBox.Location = new System.Drawing.Point(89, 60);
this.PasswordTextBox.Location = new System.Drawing.Point(101, 60);
this.PasswordTextBox.MaxLength = 256;
this.PasswordTextBox.Name = "PasswordTextBox";
this.PasswordTextBox.Size = new System.Drawing.Size(160, 21);
@@ -186,7 +220,7 @@
//
this.EncryptionLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.EncryptionLabel.AutoSize = true;
this.EncryptionLabel.Location = new System.Drawing.Point(18, 91);
this.EncryptionLabel.Location = new System.Drawing.Point(30, 113);
this.EncryptionLabel.Name = "EncryptionLabel";
this.EncryptionLabel.Size = new System.Drawing.Size(65, 12);
this.EncryptionLabel.TabIndex = 8;
@@ -219,7 +253,7 @@
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305"});
this.EncryptionSelect.Location = new System.Drawing.Point(89, 87);
this.EncryptionSelect.Location = new System.Drawing.Point(101, 109);
this.EncryptionSelect.Name = "EncryptionSelect";
this.EncryptionSelect.Size = new System.Drawing.Size(160, 20);
this.EncryptionSelect.TabIndex = 3;
@@ -228,7 +262,7 @@
//
this.TimeoutLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.TimeoutLabel.AutoSize = true;
this.TimeoutLabel.Location = new System.Drawing.Point(6, 144);
this.TimeoutLabel.Location = new System.Drawing.Point(18, 220);
this.TimeoutLabel.Name = "TimeoutLabel";
this.TimeoutLabel.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.TimeoutLabel.Size = new System.Drawing.Size(77, 12);
@@ -238,11 +272,45 @@
// TimeoutTextBox
//
this.TimeoutTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.TimeoutTextBox.Location = new System.Drawing.Point(89, 140);
this.TimeoutTextBox.Location = new System.Drawing.Point(101, 216);
this.TimeoutTextBox.MaxLength = 5;
this.TimeoutTextBox.Name = "TimeoutTextBox";
this.TimeoutTextBox.Size = new System.Drawing.Size(160, 21);
this.TimeoutTextBox.TabIndex = 11;
this.TimeoutTextBox.TabIndex = 7;
//
// PluginLabel
//
this.PluginLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PluginLabel.AutoSize = true;
this.PluginLabel.Location = new System.Drawing.Point(54, 139);
this.PluginLabel.Name = "PluginLabel";
this.PluginLabel.Size = new System.Drawing.Size(41, 12);
this.PluginLabel.TabIndex = 12;
this.PluginLabel.Text = "Plugin";
//
// PluginOptionsTextBox
//
this.PluginOptionsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PluginOptionsTextBox.Location = new System.Drawing.Point(101, 162);
this.PluginOptionsTextBox.MaxLength = 256;
this.PluginOptionsTextBox.Name = "PluginOptionsTextBox";
this.PluginOptionsTextBox.Size = new System.Drawing.Size(160, 21);
this.PluginOptionsTextBox.TabIndex = 5;
this.PluginOptionsTextBox.WordWrap = false;
//
// ShowPasswdCheckBox
//
this.ShowPasswdCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.ShowPasswdCheckBox.AutoSize = true;
this.ShowPasswdCheckBox.Location = new System.Drawing.Point(101, 87);
this.ShowPasswdCheckBox.Name = "ShowPasswdCheckBox";
this.ShowPasswdCheckBox.Size = new System.Drawing.Size(102, 16);
this.ShowPasswdCheckBox.TabIndex = 16;
this.ShowPasswdCheckBox.Text = "Show Password";
this.ShowPasswdCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.ShowPasswdCheckBox.UseVisualStyleBackColor = true;
this.ShowPasswdCheckBox.CheckedChanged += new System.EventHandler(this.ShowPasswdCheckBox_CheckedChanged);
//
// panel2
//
@@ -262,7 +330,7 @@
this.OKButton.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.OKButton.Name = "OKButton";
this.OKButton.Size = new System.Drawing.Size(75, 23);
this.OKButton.TabIndex = 12;
this.OKButton.TabIndex = 15;
this.OKButton.Text = "OK";
this.OKButton.UseVisualStyleBackColor = true;
this.OKButton.Click += new System.EventHandler(this.OKButton_Click);
@@ -275,7 +343,7 @@
this.MyCancelButton.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.MyCancelButton.Name = "MyCancelButton";
this.MyCancelButton.Size = new System.Drawing.Size(75, 23);
this.MyCancelButton.TabIndex = 13;
this.MyCancelButton.TabIndex = 16;
this.MyCancelButton.Text = "Cancel";
this.MyCancelButton.UseVisualStyleBackColor = true;
this.MyCancelButton.Click += new System.EventHandler(this.CancelButton_Click);
@@ -287,7 +355,7 @@
this.DeleteButton.Margin = new System.Windows.Forms.Padding(3, 6, 0, 3);
this.DeleteButton.Name = "DeleteButton";
this.DeleteButton.Size = new System.Drawing.Size(80, 23);
this.DeleteButton.TabIndex = 9;
this.DeleteButton.TabIndex = 11;
this.DeleteButton.Text = "&Delete";
this.DeleteButton.UseVisualStyleBackColor = true;
this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click);
@@ -299,7 +367,7 @@
this.AddButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.AddButton.Name = "AddButton";
this.AddButton.Size = new System.Drawing.Size(80, 23);
this.AddButton.TabIndex = 8;
this.AddButton.TabIndex = 10;
this.AddButton.Text = "&Add";
this.AddButton.UseVisualStyleBackColor = true;
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
@@ -312,7 +380,7 @@
this.ServerGroupBox.Location = new System.Drawing.Point(178, 0);
this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0);
this.ServerGroupBox.Name = "ServerGroupBox";
this.ServerGroupBox.Size = new System.Drawing.Size(266, 205);
this.ServerGroupBox.Size = new System.Drawing.Size(278, 281);
this.ServerGroupBox.TabIndex = 0;
this.ServerGroupBox.TabStop = false;
this.ServerGroupBox.Text = "Server";
@@ -326,7 +394,7 @@
this.ServersListBox.Margin = new System.Windows.Forms.Padding(0);
this.ServersListBox.Name = "ServersListBox";
this.ServersListBox.Size = new System.Drawing.Size(166, 148);
this.ServersListBox.TabIndex = 7;
this.ServersListBox.TabIndex = 9;
this.ServersListBox.SelectedIndexChanged += new System.EventHandler(this.ServersListBox_SelectedIndexChanged);
//
// tableLayoutPanel2
@@ -349,7 +417,7 @@
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(444, 301);
this.tableLayoutPanel2.Size = new System.Drawing.Size(456, 377);
this.tableLayoutPanel2.TabIndex = 7;
//
// tableLayoutPanel6
@@ -362,7 +430,7 @@
this.tableLayoutPanel6.Controls.Add(this.MoveDownButton, 1, 0);
this.tableLayoutPanel6.Controls.Add(this.MoveUpButton, 0, 0);
this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 269);
this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 345);
this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel6.Name = "tableLayoutPanel6";
this.tableLayoutPanel6.RowCount = 1;
@@ -377,7 +445,7 @@
this.MoveDownButton.Margin = new System.Windows.Forms.Padding(3, 6, 0, 3);
this.MoveDownButton.Name = "MoveDownButton";
this.MoveDownButton.Size = new System.Drawing.Size(80, 23);
this.MoveDownButton.TabIndex = 11;
this.MoveDownButton.TabIndex = 14;
this.MoveDownButton.Text = "Move D&own";
this.MoveDownButton.UseVisualStyleBackColor = true;
this.MoveDownButton.Click += new System.EventHandler(this.MoveDownButton_Click);
@@ -389,7 +457,7 @@
this.MoveUpButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.MoveUpButton.Name = "MoveUpButton";
this.MoveUpButton.Size = new System.Drawing.Size(80, 23);
this.MoveUpButton.TabIndex = 10;
this.MoveUpButton.TabIndex = 13;
this.MoveUpButton.Text = "Move &Up";
this.MoveUpButton.UseVisualStyleBackColor = true;
this.MoveUpButton.Click += new System.EventHandler(this.MoveUpButton_Click);
@@ -405,7 +473,7 @@
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.Controls.Add(this.ProxyPortTextBox, 1, 0);
this.tableLayoutPanel5.Controls.Add(this.ProxyPortLabel, 0, 0);
this.tableLayoutPanel5.Location = new System.Drawing.Point(248, 205);
this.tableLayoutPanel5.Location = new System.Drawing.Point(260, 281);
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
this.tableLayoutPanel5.Padding = new System.Windows.Forms.Padding(3);
@@ -425,7 +493,7 @@
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(113, 21);
this.ProxyPortTextBox.TabIndex = 6;
this.ProxyPortTextBox.TabIndex = 8;
this.ProxyPortTextBox.WordWrap = false;
//
// ProxyPortLabel
@@ -449,7 +517,7 @@
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
this.tableLayoutPanel3.Location = new System.Drawing.Point(285, 272);
this.tableLayoutPanel3.Location = new System.Drawing.Point(297, 348);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
@@ -468,7 +536,7 @@
this.tableLayoutPanel4.Controls.Add(this.DeleteButton, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.AddButton, 0, 0);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 205);
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 281);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 2;
@@ -484,7 +552,7 @@
this.DuplicateButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.DuplicateButton.Name = "DuplicateButton";
this.DuplicateButton.Size = new System.Drawing.Size(80, 23);
this.DuplicateButton.TabIndex = 10;
this.DuplicateButton.TabIndex = 12;
this.DuplicateButton.Text = "Dupli&cate";
this.DuplicateButton.UseVisualStyleBackColor = true;
this.DuplicateButton.Click += new System.EventHandler(this.DuplicateButton_Click);
@@ -497,7 +565,7 @@
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(574, 367);
this.ClientSize = new System.Drawing.Size(574, 398);
this.Controls.Add(this.tableLayoutPanel2);
this.Controls.Add(this.panel2);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@@ -535,7 +603,6 @@
private System.Windows.Forms.Label PasswordLabel;
private System.Windows.Forms.TextBox IPTextBox;
private System.Windows.Forms.TextBox ServerPortTextBox;
private System.Windows.Forms.TextBox PasswordTextBox;
private System.Windows.Forms.Label EncryptionLabel;
private System.Windows.Forms.ComboBox EncryptionSelect;
private System.Windows.Forms.Panel panel2;
@@ -559,6 +626,12 @@
private System.Windows.Forms.Button DuplicateButton;
private System.Windows.Forms.Label TimeoutLabel;
private System.Windows.Forms.TextBox TimeoutTextBox;
private System.Windows.Forms.Label PluginOptionsLabel;
private System.Windows.Forms.TextBox PluginTextBox;
private System.Windows.Forms.Label PluginLabel;
private System.Windows.Forms.TextBox PluginOptionsTextBox;
private System.Windows.Forms.CheckBox ShowPasswdCheckBox;
private System.Windows.Forms.TextBox PasswordTextBox;
}
}
+12
View File
@@ -46,7 +46,10 @@ namespace Shadowsocks.View
IPLabel.Text = I18N.GetString("Server Addr");
ServerPortLabel.Text = I18N.GetString("Server Port");
PasswordLabel.Text = I18N.GetString("Password");
ShowPasswdCheckBox.Text = I18N.GetString("Show Password");
EncryptionLabel.Text = I18N.GetString("Encryption");
PluginLabel.Text = I18N.GetString("Plugin");
PluginOptionsLabel.Text = I18N.GetString("Plugin Options");
ProxyPortLabel.Text = I18N.GetString("Proxy Port");
RemarksLabel.Text = I18N.GetString("Remarks");
TimeoutLabel.Text = I18N.GetString("Timeout(Sec)");
@@ -94,6 +97,8 @@ namespace Shadowsocks.View
}
server.password = PasswordTextBox.Text;
server.method = EncryptionSelect.Text;
server.plugin = PluginTextBox.Text;
server.plugin_opts = PluginOptionsTextBox.Text;
server.remarks = RemarksTextBox.Text;
if (!int.TryParse(TimeoutTextBox.Text, out server.timeout))
{
@@ -127,6 +132,8 @@ namespace Shadowsocks.View
PasswordTextBox.Text = server.password;
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString();
EncryptionSelect.Text = server.method ?? "aes-256-cfb";
PluginTextBox.Text = server.plugin;
PluginOptionsTextBox.Text = server.plugin_opts;
RemarksTextBox.Text = server.remarks;
TimeoutTextBox.Text = server.timeout.ToString();
}
@@ -352,5 +359,10 @@ namespace Shadowsocks.View
MoveConfigItem(+1); // +1 means move forward
}
}
private void ShowPasswdCheckBox_CheckedChanged(object sender, EventArgs e)
{
this.PasswordTextBox.UseSystemPasswordChar = !this.ShowPasswdCheckBox.Checked;
}
}
}
+108
View File
@@ -117,4 +117,112 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="tableLayoutPanel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginOptionsLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="RemarksTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="RemarksLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IPLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerPortLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PasswordLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IPTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerPortTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PasswordTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="EncryptionLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="EncryptionSelect.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="TimeoutLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="TimeoutTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginOptionsTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ShowPasswdCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="panel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="OKButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MyCancelButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DeleteButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="AddButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerGroupBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServersListBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel6.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveDownButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveUpButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel5.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel3.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel4.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DuplicateButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>
@@ -659,7 +659,7 @@ namespace Shadowsocks.View
private void QRCodeItem_Click(object sender, EventArgs e)
{
QRCodeForm qrCodeForm = new QRCodeForm(controller.GetQRCodeForCurrentServer());
QRCodeForm qrCodeForm = new QRCodeForm(controller.GetServerURLForCurrentServer());
//qrCodeForm.Icon = this.Icon;
// TODO
qrCodeForm.Show();
+79 -112
View File
@@ -28,70 +28,27 @@
/// </summary>
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.MyCancelButton = new System.Windows.Forms.Button();
this.OKButton = new System.Windows.Forms.Button();
this.UseProxyCheckBox = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyAddrLabel = new System.Windows.Forms.Label();
this.ProxyServerTextBox = new System.Windows.Forms.TextBox();
this.ProxyPortLabel = new System.Windows.Forms.Label();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyTypeLabel = new System.Windows.Forms.Label();
this.ProxyTypeComboBox = new System.Windows.Forms.ComboBox();
this.ProxyTimeoutTextBox = new System.Windows.Forms.TextBox();
this.ProxyTimeoutLabel = new System.Windows.Forms.Label();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyNotificationLabel = new System.Windows.Forms.Label();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSize = true;
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 1);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 123);
this.tableLayoutPanel1.TabIndex = 0;
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.AutoSize = true;
this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel3.ColumnCount = 2;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 94);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.Size = new System.Drawing.Size(159, 26);
this.tableLayoutPanel3.TabIndex = 9;
//
// MyCancelButton
//
this.MyCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.MyCancelButton.Dock = System.Windows.Forms.DockStyle.Right;
this.MyCancelButton.Location = new System.Drawing.Point(84, 3);
this.MyCancelButton.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.MyCancelButton.Name = "MyCancelButton";
@@ -104,7 +61,6 @@
// OKButton
//
this.OKButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.OKButton.Dock = System.Windows.Forms.DockStyle.Right;
this.OKButton.Location = new System.Drawing.Point(3, 3);
this.OKButton.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.OKButton.Name = "OKButton";
@@ -117,6 +73,7 @@
// UseProxyCheckBox
//
this.UseProxyCheckBox.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.UseProxyCheckBox, 2);
this.UseProxyCheckBox.Location = new System.Drawing.Point(3, 3);
this.UseProxyCheckBox.Name = "UseProxyCheckBox";
this.UseProxyCheckBox.Size = new System.Drawing.Size(78, 16);
@@ -125,31 +82,11 @@
this.UseProxyCheckBox.UseVisualStyleBackColor = true;
this.UseProxyCheckBox.CheckedChanged += new System.EventHandler(this.UseProxyCheckBox_CheckedChanged);
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.AutoSize = true;
this.tableLayoutPanel2.ColumnCount = 4;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.Controls.Add(this.ProxyAddrLabel, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortLabel, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 61);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27);
this.tableLayoutPanel2.TabIndex = 1;
//
// ProxyAddrLabel
//
this.ProxyAddrLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyAddrLabel.AutoSize = true;
this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 7);
this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 71);
this.ProxyAddrLabel.Name = "ProxyAddrLabel";
this.ProxyAddrLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyAddrLabel.TabIndex = 0;
@@ -158,10 +95,10 @@
// ProxyServerTextBox
//
this.ProxyServerTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 3);
this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 67);
this.ProxyServerTextBox.MaxLength = 512;
this.ProxyServerTextBox.Name = "ProxyServerTextBox";
this.ProxyServerTextBox.Size = new System.Drawing.Size(135, 21);
this.ProxyServerTextBox.Size = new System.Drawing.Size(142, 21);
this.ProxyServerTextBox.TabIndex = 1;
this.ProxyServerTextBox.WordWrap = false;
//
@@ -169,46 +106,27 @@
//
this.ProxyPortLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyPortLabel.AutoSize = true;
this.ProxyPortLabel.Location = new System.Drawing.Point(215, 7);
this.ProxyPortLabel.Location = new System.Drawing.Point(222, 71);
this.ProxyPortLabel.Name = "ProxyPortLabel";
this.ProxyPortLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyPortLabel.Size = new System.Drawing.Size(77, 12);
this.ProxyPortLabel.TabIndex = 2;
this.ProxyPortLabel.Text = "Proxy Port";
//
// ProxyPortTextBox
//
this.ProxyPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyPortTextBox.Location = new System.Drawing.Point(286, 3);
this.ProxyPortTextBox.Location = new System.Drawing.Point(305, 67);
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(100, 21);
this.ProxyPortTextBox.Size = new System.Drawing.Size(58, 21);
this.ProxyPortTextBox.TabIndex = 3;
this.ProxyPortTextBox.WordWrap = false;
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.AutoSize = true;
this.tableLayoutPanel4.ColumnCount = 4;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeLabel, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeComboBox, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTimeoutTextBox, 3, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTimeoutLabel, 2, 0);
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.Size = new System.Drawing.Size(387, 30);
this.tableLayoutPanel4.TabIndex = 10;
//
// ProxyTypeLabel
//
this.ProxyTypeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTypeLabel.AutoSize = true;
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 9);
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 40);
this.ProxyTypeLabel.Name = "ProxyTypeLabel";
this.ProxyTypeLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyTypeLabel.TabIndex = 1;
@@ -222,30 +140,86 @@
this.ProxyTypeComboBox.Items.AddRange(new object[] {
"SOCKS5",
"HTTP"});
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 5);
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 36);
this.ProxyTypeComboBox.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5);
this.ProxyTypeComboBox.Name = "ProxyTypeComboBox";
this.ProxyTypeComboBox.Size = new System.Drawing.Size(121, 20);
this.ProxyTypeComboBox.Size = new System.Drawing.Size(142, 20);
this.ProxyTypeComboBox.TabIndex = 2;
//
// ProxyTimeoutTextBox
//
this.ProxyTimeoutTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTimeoutTextBox.Location = new System.Drawing.Point(284, 4);
this.ProxyTimeoutTextBox.Location = new System.Drawing.Point(305, 36);
this.ProxyTimeoutTextBox.Name = "ProxyTimeoutTextBox";
this.ProxyTimeoutTextBox.Size = new System.Drawing.Size(100, 21);
this.ProxyTimeoutTextBox.Size = new System.Drawing.Size(58, 21);
this.ProxyTimeoutTextBox.TabIndex = 3;
//
// ProxyTimeoutLabel
//
this.ProxyTimeoutLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTimeoutLabel.AutoSize = true;
this.ProxyTimeoutLabel.Location = new System.Drawing.Point(201, 9);
this.ProxyTimeoutLabel.Location = new System.Drawing.Point(222, 40);
this.ProxyTimeoutLabel.Name = "ProxyTimeoutLabel";
this.ProxyTimeoutLabel.Size = new System.Drawing.Size(77, 12);
this.ProxyTimeoutLabel.TabIndex = 4;
this.ProxyTimeoutLabel.Text = "Timeout(Sec)";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 4;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 70F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 30F));
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.ProxyTypeLabel, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortTextBox, 3, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyTypeComboBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyTimeoutLabel, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortLabel, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyTimeoutTextBox, 3, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyServerTextBox, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyAddrLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyNotificationLabel, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 0, 4);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 5;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 34.14634F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(366, 177);
this.tableLayoutPanel1.TabIndex = 14;
//
// ProxyNotificationLabel
//
this.ProxyNotificationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyNotificationLabel.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.ProxyNotificationLabel, 4);
this.ProxyNotificationLabel.ForeColor = System.Drawing.Color.Red;
this.ProxyNotificationLabel.Location = new System.Drawing.Point(3, 111);
this.ProxyNotificationLabel.Name = "ProxyNotificationLabel";
this.ProxyNotificationLabel.Size = new System.Drawing.Size(360, 12);
this.ProxyNotificationLabel.TabIndex = 5;
this.ProxyNotificationLabel.Text = "If server has a plugin, proxy will not be used";
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoSize = true;
this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.SetColumnSpan(this.flowLayoutPanel1, 4);
this.flowLayoutPanel1.Controls.Add(this.MyCancelButton);
this.flowLayoutPanel1.Controls.Add(this.OKButton);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Right;
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
this.flowLayoutPanel1.Location = new System.Drawing.Point(204, 145);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(159, 29);
this.flowLayoutPanel1.TabIndex = 6;
//
// ProxyForm
//
this.AcceptButton = this.OKButton;
@@ -254,7 +228,7 @@
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(441, 165);
this.ClientSize = new System.Drawing.Size(448, 231);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
@@ -266,32 +240,25 @@
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ProxyForm_FormClosed);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
this.flowLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.CheckBox UseProxyCheckBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.Label ProxyAddrLabel;
private System.Windows.Forms.TextBox ProxyServerTextBox;
private System.Windows.Forms.Label ProxyPortLabel;
private System.Windows.Forms.TextBox ProxyPortTextBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Button MyCancelButton;
private System.Windows.Forms.Button OKButton;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.Label ProxyTypeLabel;
private System.Windows.Forms.ComboBox ProxyTypeComboBox;
private System.Windows.Forms.TextBox ProxyTimeoutTextBox;
private System.Windows.Forms.Label ProxyTimeoutLabel;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label ProxyNotificationLabel;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
}
}
+1
View File
@@ -36,6 +36,7 @@ namespace Shadowsocks.View
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr");
ProxyPortLabel.Text = I18N.GetString("Proxy Port");
ProxyTimeoutLabel.Text = I18N.GetString("Timeout(Sec)");
ProxyNotificationLabel.Text = I18N.GetString("If server has a plugin, proxy will not be used");
OKButton.Text = I18N.GetString("OK");
MyCancelButton.Text = I18N.GetString("Cancel");
this.Text = I18N.GetString("Edit Proxy");
+1 -1
View File
@@ -67,7 +67,7 @@ namespace Shadowsocks.View
var servers = Configuration.Load();
var serverDatas = servers.configs.Select(
server =>
new KeyValuePair<string, string>(ShadowsocksController.GetQRCode(server), server.FriendlyName())
new KeyValuePair<string, string>(ShadowsocksController.GetServerURL(server), server.FriendlyName())
).ToList();
listBox1.DataSource = serverDatas;
+4 -5
View File
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Caseless.Fody" version="1.4.2" targetFramework="net462" developmentDependency="true" />
<package id="Costura.Fody" version="1.3.3.0" targetFramework="net462" developmentDependency="true" />
<package id="Cyotek.CircularBuffer" version="1.0.2" targetFramework="net462" />
<package id="Fody" version="1.29.4" targetFramework="net462" developmentDependency="true" />
<package id="Caseless.Fody" version="1.5.0" targetFramework="net462" developmentDependency="true" />
<package id="Costura.Fody" version="1.4.1" targetFramework="net462" developmentDependency="true" />
<package id="Fody" version="2.0.9" targetFramework="net462" developmentDependency="true" />
<package id="GlobalHotKey" version="1.1.0" targetFramework="net462" />
<package id="Newtonsoft.Json" version="10.0.1" targetFramework="net462" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net462" />
<package id="StringEx.CS" version="0.3.1" targetFramework="net462" developmentDependency="true" />
<package id="ZXing.Net" version="0.15.0" targetFramework="net462" />
</packages>
+11 -11
View File
@@ -23,6 +23,8 @@
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -37,8 +39,6 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@@ -66,9 +66,6 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>3rd\Cyotek.CircularBuffer.1.0.2\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>
</Reference>
<Reference Include="GlobalHotKey, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll</HintPath>
<Private>True</Private>
@@ -76,7 +73,7 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>3rd\Newtonsoft.Json.10.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>3rd\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -100,6 +97,7 @@
<Compile Include="Encryption\AEAD\AEADEncryptor.cs" />
<Compile Include="Encryption\AEAD\AEADMbedTLSEncryptor.cs" />
<Compile Include="Encryption\AEAD\AEADSodiumEncryptor.cs" />
<Compile Include="Encryption\CircularBuffer\ByteCircularBuffer.cs" />
<Compile Include="Encryption\EncryptorBase.cs" />
<Compile Include="Encryption\EncryptorFactory.cs" />
<Compile Include="Encryption\Exception\CryptoException.cs" />
@@ -112,6 +110,7 @@
<Compile Include="Encryption\Stream\StreamSodiumEncryptor.cs" />
<Compile Include="Model\HotKeyConfig.cs" />
<Compile Include="Model\ProxyConfig.cs" />
<Compile Include="Model\SysproxyConfig.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
@@ -146,6 +145,7 @@
<Compile Include="Controller\Strategy\BalancingStrategy.cs" />
<Compile Include="Controller\Strategy\StrategyManager.cs" />
<Compile Include="Controller\Strategy\IStrategy.cs" />
<Compile Include="Controller\Service\Sip003Plugin.cs" />
<Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="Settings.cs" />
<Compile Include="StringEx.cs" />
@@ -266,9 +266,9 @@
<Content Include="Data\ja.txt" />
<Content Include="Data\privoxy_conf.txt" />
<Content Include="Data\user-rule.txt" />
<Content Include="FodyWeavers.xml">
<None Include="FodyWeavers.xml">
<SubType>Designer</SubType>
</Content>
</None>
<Content Include="Resources\ssIn24.png" />
<Content Include="Resources\ssOut24.png" />
<Content Include="shadowsocks.ico" />
@@ -342,12 +342,12 @@ foreach (var item in filesToCleanup)
<Target Name="CleanReferenceCopyLocalPaths" AfterTargets="AfterBuild;NonWinFodyTarget">
<CosturaCleanup Config="FodyWeavers.xml" Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
<Import Project="3rd\Fody.1.29.4\build\dotnet\Fody.targets" Condition="Exists('3rd\Fody.1.29.4\build\dotnet\Fody.targets')" />
<Import Project="3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets" Condition="Exists('3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
<ErrorText>此项目引用这台计算机上缺少的 NuGet 程序包。使用 NuGet 程序包还原可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('3rd\Fody.1.29.4\build\dotnet\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.1.29.4\build\dotnet\Fody.targets'))" />
<Error Condition="!Exists('3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
+223 -7
View File
@@ -8,6 +8,7 @@ using System.Threading;
using System.Collections.Generic;
using Shadowsocks.Controller.Hotkeys;
using Shadowsocks.Encryption.Stream;
using Shadowsocks.Model;
namespace test
{
@@ -26,12 +27,13 @@ namespace test
Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3.2", "1.3.1") > 0);
}
[ TestMethod ]
public void TestHotKey2Str() {
Assert.AreEqual( "Ctrl+A", HotKeys.HotKey2Str( Key.A, ModifierKeys.Control ) );
Assert.AreEqual( "Ctrl+Alt+D2", HotKeys.HotKey2Str( Key.D2, (ModifierKeys.Alt | ModifierKeys.Control) ) );
Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift)));
Assert.AreEqual( "Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str( Key.F6, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift)));
[TestMethod]
public void TestHotKey2Str()
{
Assert.AreEqual("Ctrl+A", HotKeys.HotKey2Str(Key.A, ModifierKeys.Control));
Assert.AreEqual("Ctrl+Alt+D2", HotKeys.HotKey2Str(Key.D2, (ModifierKeys.Alt | ModifierKeys.Control)));
Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
Assert.AreEqual("Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
Assert.AreNotEqual("Ctrl+Shift+Alt+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
}
@@ -41,7 +43,7 @@ namespace test
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+A").Equals(new HotKey(Key.A, ModifierKeys.Control)));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Shift))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt| ModifierKeys.Shift))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
HotKey testKey0 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+A");
Assert.IsTrue(testKey0 != null && testKey0.Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
HotKey testKey1 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+F2");
@@ -224,5 +226,219 @@ namespace test
throw;
}
}
[TestMethod]
public void ParseAndGenerateShadowsocksUrl()
{
var server = new Server
{
server = "192.168.100.1",
server_port = 8888,
password = "test",
method = "bf-cfb"
};
var serverCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4";
var server2 = new Server
{
server = "192.168.1.1",
server_port = 8388,
password = "test",
method = "bf-cfb"
};
var server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==";
var serverWithRemark = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
remarks = "example-server"
};
var serverWithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server";
var server2WithRemark = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
remarks = "example-server"
};
var server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server";
var serverWithPlugin = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
plugin = "obfs-local",
plugin_opts = "obfs=http;obfs-host=google.com"
};
var serverWithPluginCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
var server2WithPlugin = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
plugin = "obfs-local",
plugin_opts = "obfs=http;obfs-host=google.com"
};
var server2WithPluginCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
var serverWithPluginAndRemark = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
plugin = serverWithPlugin.plugin,
plugin_opts = serverWithPlugin.plugin_opts,
remarks = serverWithRemark.remarks
};
var serverWithPluginAndRemarkCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
var server2WithPluginAndRemark = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
plugin = server2WithPlugin.plugin,
plugin_opts = server2WithPlugin.plugin_opts,
remarks = server2WithRemark.remarks
};
var server2WithPluginAndRemarkCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
serverCanonUrl,
"\r\n",
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/",
serverWithRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server"),
new[]
{
server,
server,
serverWithRemark,
serverWithRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
server2CanonUrl,
"\r\n",
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/",
server2WithRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server"),
new[]
{
server2,
server2,
server2WithRemark,
server2WithRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888",
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server",
serverWithPluginCanonUrl,
serverWithPluginAndRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
new[]
{
server,
server,
serverWithRemark,
serverWithRemark,
serverWithPlugin,
serverWithPluginAndRemark,
serverWithPluginAndRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388",
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server",
server2WithPluginCanonUrl,
server2WithPluginAndRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
new[]
{
server2,
server2,
server2WithRemark,
server2WithRemark,
server2WithPlugin,
server2WithPluginAndRemark,
server2WithPluginAndRemark
});
var generateUrlCases = new Dictionary<string, Server>
{
[serverCanonUrl] = server,
[serverWithRemarkCanonUrl] = serverWithRemark,
[serverWithPluginCanonUrl] = serverWithPlugin,
[serverWithPluginAndRemarkCanonUrl] = serverWithPluginAndRemark
};
RunGenerateShadowsocksUrlTest(generateUrlCases);
}
private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList<Server> expected)
{
var actual = Server.GetServers(testCase);
if (actual.Count != expected.Count)
{
Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count);
}
for (int i = 0; i < expected.Count; i++)
{
var expectedServer = expected[i];
var actualServer = actual[i];
Assert.AreEqual(expectedServer.server, actualServer.server);
Assert.AreEqual(expectedServer.server_port, actualServer.server_port);
Assert.AreEqual(expectedServer.password, actualServer.password);
Assert.AreEqual(expectedServer.method, actualServer.method);
Assert.AreEqual(expectedServer.plugin, actualServer.plugin);
Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts);
Assert.AreEqual(expectedServer.remarks, actualServer.remarks);
Assert.AreEqual(expectedServer.timeout, actualServer.timeout);
}
}
private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary<string, Server> testCases)
{
foreach (var testCase in testCases)
{
string expected = testCase.Key;
Server config = testCase.Value;
var actual = ShadowsocksController.GetServerURL(config);
Assert.AreEqual(expected, actual);
}
}
}
}