From 5846c9dc93a1120d438114b13b32af1265ea6f5e Mon Sep 17 00:00:00 2001 From: Student Main Date: Sat, 18 Apr 2020 01:36:32 +0800 Subject: [PATCH 1/9] named pipe for url ipc --- .../Controller/Service/PipeServer.cs | 29 ++++++ shadowsocks-csharp/Program.cs | 88 +++++++++++++------ shadowsocks-csharp/shadowsocks-csharp.csproj | 1 + 3 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 shadowsocks-csharp/Controller/Service/PipeServer.cs diff --git a/shadowsocks-csharp/Controller/Service/PipeServer.cs b/shadowsocks-csharp/Controller/Service/PipeServer.cs new file mode 100644 index 00000000..fb2e1e0d --- /dev/null +++ b/shadowsocks-csharp/Controller/Service/PipeServer.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using System.IO.Pipes; +using System.Net; +using System.Text; + +namespace Shadowsocks.Controller +{ + internal class PipeServer + { + public async void Run(string path) + { + byte[] buf = new byte[4096]; + while (true) + { + using (NamedPipeServerStream stream = new NamedPipeServerStream(path)) + { + stream.WaitForConnection(); + await stream.ReadAsync(buf, 0, 4); + int strlen = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); + await stream.ReadAsync(buf, 0, strlen); + string url = Encoding.UTF8.GetString(buf, 0, strlen); + Console.WriteLine(url); + stream.Close(); + } + } + } + } +} diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 5b723acd..8fe8646a 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -10,6 +10,12 @@ using Shadowsocks.Controller; using Shadowsocks.Controller.Hotkeys; using Shadowsocks.Util; using Shadowsocks.View; +using System.Linq; +using System.IO.Pipes; +using System.Text; +using System.Net; +using System.Threading.Tasks; +using System.Collections.Generic; namespace Shadowsocks { @@ -55,22 +61,36 @@ namespace Shadowsocks } return; } + string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; - Utils.ReleaseMemory(true); - using (Mutex mutex = new Mutex(false, $"Global\\Shadowsocks_{Application.StartupPath.GetHashCode()}")) + using (NamedPipeClientStream pipe = new NamedPipeClientStream(pipename)) { - Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); - // handle UI exceptions - Application.ThreadException += Application_ThreadException; - // handle non-UI exceptions - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - Application.ApplicationExit += Application_ApplicationExit; - SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - AutoStartup.RegisterForRestart(true); - - if (!mutex.WaitOne(0, false)) + bool pipeExist = false; + try + { + pipe.Connect(10); + pipeExist = true; + } + catch (TimeoutException) + { + pipeExist = false; + } + + var alist = Args.ToList(); + int urlidx = alist.IndexOf("--open-url") + 1; + if (urlidx > 0) + { + if (Args.Length <= urlidx) return; + if (!pipeExist) return; + + byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); + byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); + pipe.Write(blen, 0, 4); + pipe.Write(b, 0, b.Length); + pipe.Close(); + return; + } + else if (pipeExist) { Process[] oldProcesses = Process.GetProcessesByName("Shadowsocks"); if (oldProcesses.Length > 0) @@ -83,21 +103,37 @@ namespace Shadowsocks I18N.GetString("Shadowsocks is already running.")); return; } - Directory.SetCurrentDirectory(Application.StartupPath); - + } + + Task.Run(() => new PipeServer().Run(pipename)); + + Utils.ReleaseMemory(true); + + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + // handle UI exceptions + Application.ThreadException += Application_ThreadException; + // handle non-UI exceptions + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + Application.ApplicationExit += Application_ApplicationExit; + SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + AutoStartup.RegisterForRestart(true); + + Directory.SetCurrentDirectory(Application.StartupPath); + #if DEBUG - // truncate privoxy log file while debugging - string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); - if (File.Exists(privoxyLogFilename)) - using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } + // truncate privoxy log file while debugging + string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); + if (File.Exists(privoxyLogFilename)) + using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } #endif - MainController = new ShadowsocksController(); - MenuController = new MenuViewController(MainController); + MainController = new ShadowsocksController(); + MenuController = new MenuViewController(MainController); - HotKeys.Init(MainController); - MainController.Start(); - Application.Run(); - } + HotKeys.Init(MainController); + MainController.Start(); + Application.Run(); } private static int exited = 0; diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index bf562337..83dd3ecf 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -113,6 +113,7 @@ + From e492bc02f482ca96fafff154d1725cbcb1816d24 Mon Sep 17 00:00:00 2001 From: Student Main Date: Sat, 18 Apr 2020 01:50:57 +0800 Subject: [PATCH 2/9] pass received url to controller --- .../Controller/Service/PipeServer.cs | 27 ++++++++++++++++--- shadowsocks-csharp/Program.cs | 9 +++++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/shadowsocks-csharp/Controller/Service/PipeServer.cs b/shadowsocks-csharp/Controller/Service/PipeServer.cs index fb2e1e0d..fd535b48 100644 --- a/shadowsocks-csharp/Controller/Service/PipeServer.cs +++ b/shadowsocks-csharp/Controller/Service/PipeServer.cs @@ -6,8 +6,20 @@ using System.Text; namespace Shadowsocks.Controller { + class RequestAddUrlEventArgs : EventArgs + { + public readonly string Url; + + public RequestAddUrlEventArgs(string url) + { + this.Url = url; + } + } + + internal class PipeServer { + public event EventHandler AddUrlRequested; public async void Run(string path) { byte[] buf = new byte[4096]; @@ -17,10 +29,17 @@ namespace Shadowsocks.Controller { stream.WaitForConnection(); await stream.ReadAsync(buf, 0, 4); - int strlen = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); - await stream.ReadAsync(buf, 0, strlen); - string url = Encoding.UTF8.GetString(buf, 0, strlen); - Console.WriteLine(url); + int opcode = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); + if (opcode == 1) + { + await stream.ReadAsync(buf, 0, 4); + int strlen = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0)); + + await stream.ReadAsync(buf, 0, strlen); + string url = Encoding.UTF8.GetString(buf, 0, strlen); + + AddUrlRequested?.Invoke(this, new RequestAddUrlEventArgs(url)); + } stream.Close(); } } diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 8fe8646a..cc4c1ea5 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -84,7 +84,9 @@ namespace Shadowsocks if (!pipeExist) return; byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); + byte[] opAddUrl = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(1)); byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); + pipe.Write(opAddUrl, 0, 4); // opcode addurl pipe.Write(blen, 0, 4); pipe.Write(b, 0, b.Length); pipe.Close(); @@ -105,8 +107,6 @@ namespace Shadowsocks } } - Task.Run(() => new PipeServer().Run(pipename)); - Utils.ReleaseMemory(true); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); @@ -133,6 +133,11 @@ namespace Shadowsocks HotKeys.Init(MainController); MainController.Start(); + + PipeServer pipeServer = new PipeServer(); + Task.Run(() => pipeServer.Run(pipename)); + pipeServer.AddUrlRequested += (_1, e) => MainController.AddServerBySSURL(e.Url); + Application.Run(); } From 7c22506eb1468f6f991bbdd8c8af1002e859f478 Mon Sep 17 00:00:00 2001 From: Student Main Date: Sat, 18 Apr 2020 02:45:07 +0800 Subject: [PATCH 3/9] add protocol handler in registry --- .../Controller/System/ProtocolHandler.cs | 106 ++++++++++++++++++ shadowsocks-csharp/Program.cs | 9 +- shadowsocks-csharp/View/MenuViewController.cs | 13 +++ shadowsocks-csharp/shadowsocks-csharp.csproj | 1 + 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 shadowsocks-csharp/Controller/System/ProtocolHandler.cs diff --git a/shadowsocks-csharp/Controller/System/ProtocolHandler.cs b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs new file mode 100644 index 00000000..f9dcc81e --- /dev/null +++ b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs @@ -0,0 +1,106 @@ +using Microsoft.Win32; +using NLog; +using Shadowsocks.Util; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Shadowsocks.Controller +{ + static class ProtocolHandler + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // Don't use Application.ExecutablePath + // see https://stackoverflow.com/questions/12945805/odd-c-sharp-path-issue + private static readonly string ExecutablePath = Assembly.GetEntryAssembly().Location; + + // TODO: Elevate when necessary + public static bool Set(bool enabled) + { + RegistryKey runKey = null; + try + { + RegistryKey hkcr = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, + Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32); + + runKey = hkcr.CreateSubKey("ss",RegistryKeyPermissionCheck.ReadWriteSubTree); + if (runKey == null) + { + logger.Error(@"Cannot find HKCR\ss"); + return false; + } + if (enabled) + { + runKey.SetValue("", "URL:Shadowsocks"); + runKey.SetValue("URL Protocol", ""); + var shellOpen = runKey.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command"); + shellOpen.SetValue("", $"{ExecutablePath} --open-url %1"); + + } + else + { + hkcr.DeleteSubKeyTree("ss"); + } + return true; + } + catch (Exception e) + { + logger.LogUsefulException(e); + return false; + } + finally + { + if (runKey != null) + { + try + { + runKey.Close(); + runKey.Dispose(); + } + catch (Exception e) + { logger.LogUsefulException(e); } + } + } + } + + public static bool Check() + { + RegistryKey runKey = null; + try + { + runKey = Utils.OpenRegKey(@"ss", true, RegistryHive.ClassesRoot); + if (runKey == null) + { + logger.Error(@"Cannot find HKCR\ss"); + return false; + } + + var shellOpen = runKey.OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command"); + return (string)shellOpen.GetValue("") == $"{ExecutablePath} --open-url %1"; + } + catch (Exception e) + { + logger.LogUsefulException(e); + return false; + } + finally + { + if (runKey != null) + { + try + { + runKey.Close(); + runKey.Dispose(); + } + catch (Exception e) + { logger.LogUsefulException(e); } + } + } + } + + } +} diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index cc4c1ea5..10c6d9fb 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -136,7 +136,14 @@ namespace Shadowsocks PipeServer pipeServer = new PipeServer(); Task.Run(() => pipeServer.Run(pipename)); - pipeServer.AddUrlRequested += (_1, e) => MainController.AddServerBySSURL(e.Url); + pipeServer.AddUrlRequested += (_1, e) => + { + var dr = MessageBox.Show($"Open url: {e.Url} ?", "Shadowsocks", MessageBoxButtons.YesNo); + if (dr == DialogResult.Yes) + { + MainController.AddServerBySSURL(e.Url); + } + }; Application.Run(); } diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index ddcf21f4..72147693 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -36,6 +36,7 @@ namespace Shadowsocks.View private ContextMenu contextMenu1; private MenuItem disableItem; private MenuItem AutoStartupItem; + private MenuItem ProtocolHandlerItem; private MenuItem ShareOverLANItem; private MenuItem SeperatorItem; private MenuItem ConfigItem; @@ -315,6 +316,7 @@ namespace Shadowsocks.View this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), new MenuItem("-"), this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), + this.ProtocolHandlerItem = CreateMenuItem("Start on Boot", new EventHandler(this.ProtocolHandlerItem_Click)), this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)), new MenuItem("-"), this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), @@ -442,6 +444,7 @@ namespace Shadowsocks.View VerboseLoggingToggleItem.Checked = config.isVerboseLogging; ShowPluginOutputToggleItem.Checked = config.showPluginOutput; AutoStartupItem.Checked = AutoStartup.Check(); + ProtocolHandlerItem.Checked = ProtocolHandler.Check(); onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac; localPACItem.Checked = !onlinePACItem.Checked; secureLocalPacUrlToggleItem.Checked = config.secureLocalPac; @@ -845,6 +848,16 @@ namespace Shadowsocks.View { MessageBox.Show(I18N.GetString("Failed to update registry")); } + LoadCurrentConfiguration(); + } + private void ProtocolHandlerItem_Click(object sender, EventArgs e) + { + ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; + if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) + { + MessageBox.Show(I18N.GetString("Failed to update registry")); + } + LoadCurrentConfiguration(); } private void LocalPACItem_Click(object sender, EventArgs e) diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 83dd3ecf..553573dc 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -114,6 +114,7 @@ + From 1e92b30fe5f30808a39c1696d9f2d5493000b46e Mon Sep 17 00:00:00 2001 From: Student Main Date: Sat, 18 Apr 2020 12:12:47 +0800 Subject: [PATCH 4/9] add from url without another instance also with some i18n update --- .../Controller/ShadowsocksController.cs | 10 +++ shadowsocks-csharp/Program.cs | 81 +++++++++++-------- shadowsocks-csharp/View/MenuViewController.cs | 4 +- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index f4ea1294..ccf08858 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -218,6 +218,16 @@ namespace Shadowsocks.Controller StatisticsStrategyConfiguration.Save(configuration); } + public void AskAddServerBySSURL(string ssURL) + { + var dr = MessageBox.Show(I18N.GetString("Open url: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo); + if (dr == DialogResult.Yes) + { + AddServerBySSURL(ssURL); + } + } + + public bool AddServerBySSURL(string ssURL) { try diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 10c6d9fb..653ee448 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -1,27 +1,26 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Windows.Forms; +using Microsoft.Win32; using NLog; -using Microsoft.Win32; - using Shadowsocks.Controller; using Shadowsocks.Controller.Hotkeys; using Shadowsocks.Util; using Shadowsocks.View; -using System.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.IO.Pipes; -using System.Text; +using System.Linq; using System.Net; +using System.Text; +using System.Threading; using System.Threading.Tasks; -using System.Collections.Generic; +using System.Windows.Forms; namespace Shadowsocks { - static class Program + internal static class Program { - private static Logger logger = LogManager.GetCurrentClassLogger(); + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); public static ShadowsocksController MainController { get; private set; } public static MenuViewController MenuController { get; private set; } public static string[] Args { get; private set; } @@ -30,15 +29,15 @@ namespace Shadowsocks /// /// [STAThread] - static void Main(string[] args) + private static void Main(string[] args) { Directory.SetCurrentDirectory(Application.StartupPath); // todo: initialize the NLog configuartion Model.NLogConfig.TouchAndApplyNLogConfig(); // .NET Framework 4.7.2 on Win7 compatibility - System.Net.ServicePointManager.SecurityProtocol |= - System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12; + ServicePointManager.SecurityProtocol |= + SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; // store args for further use Args = args; @@ -56,13 +55,14 @@ namespace Shadowsocks if (DialogResult.OK == MessageBox.Show(I18N.GetString("Unsupported .NET Framework, please update to {0} or later.", "4.7.2"), "Shadowsocks Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)) { - //Process.Start("https://www.microsoft.com/download/details.aspx?id=53344"); // 4.6.2 Process.Start("https://dotnet.microsoft.com/download/dotnet-framework/net472"); } return; } string pipename = $"Shadowsocks\\{Application.StartupPath.GetHashCode()}"; + string addedUrl = null; + using (NamedPipeClientStream pipe = new NamedPipeClientStream(pipename)) { bool pipeExist = false; @@ -76,22 +76,36 @@ namespace Shadowsocks pipeExist = false; } - var alist = Args.ToList(); + // TODO: switch to better argv parser when it's getting complicate + List alist = Args.ToList(); + // check --open-url param int urlidx = alist.IndexOf("--open-url") + 1; if (urlidx > 0) { - if (Args.Length <= urlidx) return; - if (!pipeExist) return; + if (Args.Length <= urlidx) + { + return; + } - byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); - byte[] opAddUrl = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(1)); - byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); - pipe.Write(opAddUrl, 0, 4); // opcode addurl - pipe.Write(blen, 0, 4); - pipe.Write(b, 0, b.Length); - pipe.Close(); - return; + // --open-url exist, and no other instance, add it later + if (!pipeExist) + { + addedUrl = Args[urlidx]; + } + // has other instance, send url via pipe then exit + else + { + byte[] b = Encoding.UTF8.GetBytes(Args[urlidx]); + byte[] opAddUrl = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(1)); + byte[] blen = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(b.Length)); + pipe.Write(opAddUrl, 0, 4); // opcode addurl + pipe.Write(blen, 0, 4); + pipe.Write(b, 0, b.Length); + pipe.Close(); + return; + } } + // has another instance, and no need to communicate with it return else if (pipeExist) { Process[] oldProcesses = Process.GetProcessesByName("Shadowsocks"); @@ -136,14 +150,11 @@ namespace Shadowsocks PipeServer pipeServer = new PipeServer(); Task.Run(() => pipeServer.Run(pipename)); - pipeServer.AddUrlRequested += (_1, e) => + pipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); + if (!addedUrl.IsNullOrEmpty()) { - var dr = MessageBox.Show($"Open url: {e.Url} ?", "Shadowsocks", MessageBoxButtons.YesNo); - if (dr == DialogResult.Yes) - { - MainController.AddServerBySSURL(e.Url); - } - }; + MainController.AskAddServerBySSURL(addedUrl); + } Application.Run(); } @@ -183,7 +194,7 @@ namespace Shadowsocks logger.Info("os wake up"); if (MainController != null) { - System.Threading.Tasks.Task.Factory.StartNew(() => + Task.Factory.StartNew(() => { Thread.Sleep(10 * 1000); try diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 72147693..5014d392 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -316,7 +316,7 @@ namespace Shadowsocks.View this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), new MenuItem("-"), this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), - this.ProtocolHandlerItem = CreateMenuItem("Start on Boot", new EventHandler(this.ProtocolHandlerItem_Click)), + this.ProtocolHandlerItem = CreateMenuItem("Register ss:// protocol", new EventHandler(this.ProtocolHandlerItem_Click)), this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)), new MenuItem("-"), this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), @@ -855,7 +855,7 @@ namespace Shadowsocks.View ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) { - MessageBox.Show(I18N.GetString("Failed to update registry")); + MessageBox.Show(I18N.GetString("Failed to update registry, try run as Admin")); } LoadCurrentConfiguration(); } From 183a0b7285cd1792acd8a76e551bc0dac33ced37 Mon Sep 17 00:00:00 2001 From: database64128 Date: Sat, 18 Apr 2020 15:15:39 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=8C=90=20Translations=20related=20to?= =?UTF-8?q?=20ss://=20association.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shadowsocks-csharp/Controller/ShadowsocksController.cs | 2 +- shadowsocks-csharp/Data/i18n.csv | 3 +++ shadowsocks-csharp/View/MenuViewController.cs | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index ccf08858..c05d8686 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -220,7 +220,7 @@ namespace Shadowsocks.Controller public void AskAddServerBySSURL(string ssURL) { - var dr = MessageBox.Show(I18N.GetString("Open url: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo); + var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) { AddServerBySSURL(ssURL); diff --git a/shadowsocks-csharp/Data/i18n.csv b/shadowsocks-csharp/Data/i18n.csv index d526b2dc..5c0ec953 100644 --- a/shadowsocks-csharp/Data/i18n.csv +++ b/shadowsocks-csharp/Data/i18n.csv @@ -18,6 +18,7 @@ Servers,Серверы,服务器,伺服器,サーバー,서버 Edit Servers...,Редактировать серверы…,编辑服务器...,編輯伺服器...,サーバーの編集...,서버 수정… Statistics Config...,Настройки статистики…,统计配置...,統計設定檔...,統計情報の設定...,통계 설정 Start on Boot,Автозагрузка,开机启动,開機啟動,システムと同時に起動,시스템 시작 시에 시작하기 +Associate ss:// Links,Ассоциированный ss:// Ссылки,关联 ss:// 链接,關聯 ss:// 鏈接,, Forward Proxy...,Прямой прокси…,正向代理设置...,正向 Proxy 設定...,フォワードプロキシの設定...,포워드 프록시 Allow other Devices to connect,Общий доступ к подключению,允许其他设备连入,允許其他裝置連入,他のデバイスからの接続を許可する,다른 기기에서 연결 허용 Local PAC,Локальный PAC,使用本地 PAC,使用本機 PAC,ローカル PAC,로컬 PAC @@ -184,6 +185,8 @@ Find Shadowsocks icon in your notify tray.,Значок Shadowsocks можно "If you want to start multiple Shadowsocks, make a copy in another directory.","Если вы хотите запустить несколько копий Shadowsocks одновременно, создайте отдельную папку на каждую копию.",如果想同时启动多个,可以另外复制一份到别的目录。,如果想同時啟動多個,可以另外複製一份至別的目錄。,複数起動したい場合は、プログラムファイルを別のフォルダーにコピーしてから、もう一度実行して下さい。,"만약 여러 개의 Shadowsocks를 사용하고 싶으시다면, 파일을 다른 곳에 복사해주세요." Failed to decode QRCode,Не удалось распознать QRCode,无法解析二维码,QR 碼解碼失敗,QR コードの読み取りに失敗しました。,QR코드를 해석하는데에 실패했습니다. Failed to update registry,Не удалось обновить запись в реестре,无法修改注册表,無法修改登錄檔,レジストリの更新に失敗しました。,레지스트리를 업데이트하는데에 실패했습니다. +Failed to update registry. Try running as administrator.,Не удалось обновить запись в реестр. Попробуйте запустить от имени администратора.,注册表更新失败,尝试以管理员身份运行。,無法修改登錄檔,嘗試以管理員身份運行。,, +Import from URL: {0} ?,импортировать из адреса: {0} ?,从URL导入: {0} ?,從URL匯入: {0} ?,, System Proxy On: ,Системный прокси:,系统代理已启用:,系統 Proxy 已啟用:,システム プロキシが有効:,시스템 프록시 활성화됨: Running: Port {0},Запущен на порту {0},正在运行:端口 {0},正在執行:連接埠號碼 {0},実行中:ポート {0},실행 중: 포트 {0}번 "Unexpected error, shadowsocks will exit. Please report to","Непредвиденная ошибка, пожалуйста сообщите на",非预期错误,Shadowsocks将退出。请提交此错误到,非預期錯誤,Shadowsocks 將結束。請報告此錯誤至,予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:,알 수 없는 오류로 Shadowsocks가 종료될 것입니다. 오류를 제보해주세요: diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 5014d392..a54656e1 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -316,7 +316,7 @@ namespace Shadowsocks.View this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)), new MenuItem("-"), this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), - this.ProtocolHandlerItem = CreateMenuItem("Register ss:// protocol", new EventHandler(this.ProtocolHandlerItem_Click)), + this.ProtocolHandlerItem = CreateMenuItem("Associate ss:// Links", new EventHandler(this.ProtocolHandlerItem_Click)), this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)), new MenuItem("-"), this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), @@ -855,7 +855,7 @@ namespace Shadowsocks.View ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) { - MessageBox.Show(I18N.GetString("Failed to update registry, try run as Admin")); + MessageBox.Show(I18N.GetString("Failed to update registry. Try running as administrator.")); } LoadCurrentConfiguration(); } From ee586d88043da8a054fcd3ff77f99f8d8564d3ef Mon Sep 17 00:00:00 2001 From: database64128 Date: Sat, 18 Apr 2020 22:27:04 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20the=20issue=20where?= =?UTF-8?q?=20associating=20ss://=20links=20requires=20admin=20privilege.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/System/ProtocolHandler.cs | 44 +++++++++---------- shadowsocks-csharp/Data/i18n.csv | 1 - shadowsocks-csharp/View/MenuViewController.cs | 2 +- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/shadowsocks-csharp/Controller/System/ProtocolHandler.cs b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs index f9dcc81e..e7cf68da 100644 --- a/shadowsocks-csharp/Controller/System/ProtocolHandler.cs +++ b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs @@ -21,29 +21,27 @@ namespace Shadowsocks.Controller // TODO: Elevate when necessary public static bool Set(bool enabled) { - RegistryKey runKey = null; + RegistryKey ssURLAssociation = null; try { - RegistryKey hkcr = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, - Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32); - - runKey = hkcr.CreateSubKey("ss",RegistryKeyPermissionCheck.ReadWriteSubTree); - if (runKey == null) + ssURLAssociation = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Classes\ss", RegistryKeyPermissionCheck.ReadWriteSubTree); + if (ssURLAssociation == null) { - logger.Error(@"Cannot find HKCR\ss"); + logger.Error(@"Failed to create HKCU\SOFTWARE\Classes\ss"); return false; } if (enabled) { - runKey.SetValue("", "URL:Shadowsocks"); - runKey.SetValue("URL Protocol", ""); - var shellOpen = runKey.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command"); + ssURLAssociation.SetValue("", "URL:Shadowsocks"); + ssURLAssociation.SetValue("URL Protocol", ""); + var shellOpen = ssURLAssociation.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command"); shellOpen.SetValue("", $"{ExecutablePath} --open-url %1"); - + logger.Info(@"Successfully added ss:// association."); } else { - hkcr.DeleteSubKeyTree("ss"); + Registry.CurrentUser.DeleteSubKeyTree(@"SOFTWARE\Classes\ss"); + logger.Info(@"Successfully removed ss:// association."); } return true; } @@ -54,12 +52,12 @@ namespace Shadowsocks.Controller } finally { - if (runKey != null) + if (ssURLAssociation != null) { try { - runKey.Close(); - runKey.Dispose(); + ssURLAssociation.Close(); + ssURLAssociation.Dispose(); } catch (Exception e) { logger.LogUsefulException(e); } @@ -69,17 +67,17 @@ namespace Shadowsocks.Controller public static bool Check() { - RegistryKey runKey = null; + RegistryKey ssURLAssociation = null; try { - runKey = Utils.OpenRegKey(@"ss", true, RegistryHive.ClassesRoot); - if (runKey == null) + ssURLAssociation = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Classes\ss", true); + if (ssURLAssociation == null) { - logger.Error(@"Cannot find HKCR\ss"); + //logger.Info(@"ss:// links not associated."); return false; } - var shellOpen = runKey.OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command"); + var shellOpen = ssURLAssociation.OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command"); return (string)shellOpen.GetValue("") == $"{ExecutablePath} --open-url %1"; } catch (Exception e) @@ -89,12 +87,12 @@ namespace Shadowsocks.Controller } finally { - if (runKey != null) + if (ssURLAssociation != null) { try { - runKey.Close(); - runKey.Dispose(); + ssURLAssociation.Close(); + ssURLAssociation.Dispose(); } catch (Exception e) { logger.LogUsefulException(e); } diff --git a/shadowsocks-csharp/Data/i18n.csv b/shadowsocks-csharp/Data/i18n.csv index 5c0ec953..e642efa2 100644 --- a/shadowsocks-csharp/Data/i18n.csv +++ b/shadowsocks-csharp/Data/i18n.csv @@ -185,7 +185,6 @@ Find Shadowsocks icon in your notify tray.,Значок Shadowsocks можно "If you want to start multiple Shadowsocks, make a copy in another directory.","Если вы хотите запустить несколько копий Shadowsocks одновременно, создайте отдельную папку на каждую копию.",如果想同时启动多个,可以另外复制一份到别的目录。,如果想同時啟動多個,可以另外複製一份至別的目錄。,複数起動したい場合は、プログラムファイルを別のフォルダーにコピーしてから、もう一度実行して下さい。,"만약 여러 개의 Shadowsocks를 사용하고 싶으시다면, 파일을 다른 곳에 복사해주세요." Failed to decode QRCode,Не удалось распознать QRCode,无法解析二维码,QR 碼解碼失敗,QR コードの読み取りに失敗しました。,QR코드를 해석하는데에 실패했습니다. Failed to update registry,Не удалось обновить запись в реестре,无法修改注册表,無法修改登錄檔,レジストリの更新に失敗しました。,레지스트리를 업데이트하는데에 실패했습니다. -Failed to update registry. Try running as administrator.,Не удалось обновить запись в реестр. Попробуйте запустить от имени администратора.,注册表更新失败,尝试以管理员身份运行。,無法修改登錄檔,嘗試以管理員身份運行。,, Import from URL: {0} ?,импортировать из адреса: {0} ?,从URL导入: {0} ?,從URL匯入: {0} ?,, System Proxy On: ,Системный прокси:,系统代理已启用:,系統 Proxy 已啟用:,システム プロキシが有効:,시스템 프록시 활성화됨: Running: Port {0},Запущен на порту {0},正在运行:端口 {0},正在執行:連接埠號碼 {0},実行中:ポート {0},실행 중: 포트 {0}번 diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index a54656e1..da65ec59 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -855,7 +855,7 @@ namespace Shadowsocks.View ProtocolHandlerItem.Checked = !ProtocolHandlerItem.Checked; if (!ProtocolHandler.Set(ProtocolHandlerItem.Checked)) { - MessageBox.Show(I18N.GetString("Failed to update registry. Try running as administrator.")); + MessageBox.Show(I18N.GetString("Failed to update registry")); } LoadCurrentConfiguration(); } From a1e4245b3a4006229eaf7434dd4e5898cf059053 Mon Sep 17 00:00:00 2001 From: database64128 Date: Sun, 19 Apr 2020 14:42:19 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=F0=9F=92=AC=20Added=20MessageBox=20for=20s?= =?UTF-8?q?s://=20import=20result.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/ShadowsocksController.cs | 13 +++++++++++-- shadowsocks-csharp/Data/i18n.csv | 2 ++ shadowsocks-csharp/View/MenuViewController.cs | 3 +-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index c05d8686..e1df6186 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -218,13 +218,22 @@ namespace Shadowsocks.Controller StatisticsStrategyConfiguration.Save(configuration); } - public void AskAddServerBySSURL(string ssURL) + public bool AskAddServerBySSURL(string ssURL) { var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) { - AddServerBySSURL(ssURL); + if (AddServerBySSURL(ssURL)) + { + MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL)); + return true; + } + else + { + MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid.")); + } } + return false; } diff --git a/shadowsocks-csharp/Data/i18n.csv b/shadowsocks-csharp/Data/i18n.csv index e642efa2..dec8aa8b 100644 --- a/shadowsocks-csharp/Data/i18n.csv +++ b/shadowsocks-csharp/Data/i18n.csv @@ -186,6 +186,8 @@ Find Shadowsocks icon in your notify tray.,Значок Shadowsocks можно Failed to decode QRCode,Не удалось распознать QRCode,无法解析二维码,QR 碼解碼失敗,QR コードの読み取りに失敗しました。,QR코드를 해석하는데에 실패했습니다. Failed to update registry,Не удалось обновить запись в реестре,无法修改注册表,無法修改登錄檔,レジストリの更新に失敗しました。,레지스트리를 업데이트하는데에 실패했습니다. Import from URL: {0} ?,импортировать из адреса: {0} ?,从URL导入: {0} ?,從URL匯入: {0} ?,, +Successfully imported from {0},Успешно импортировано из {0},导入成功:{0},導入成功:{0},, +Failed to import. Please check if the link is valid.,,导入失败,请检查链接是否有效。,導入失敗,請檢查鏈接是否有效。,, System Proxy On: ,Системный прокси:,系统代理已启用:,系統 Proxy 已啟用:,システム プロキシが有効:,시스템 프록시 활성화됨: Running: Port {0},Запущен на порту {0},正在运行:端口 {0},正在執行:連接埠號碼 {0},実行中:ポート {0},실행 중: 포트 {0}번 "Unexpected error, shadowsocks will exit. Please report to","Непредвиденная ошибка, пожалуйста сообщите на",非预期错误,Shadowsocks将退出。请提交此错误到,非預期錯誤,Shadowsocks 將結束。請報告此錯誤至,予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:,알 수 없는 오류로 Shadowsocks가 종료될 것입니다. 오류를 제보해주세요: diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index da65ec59..253c54c2 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -824,8 +824,7 @@ namespace Shadowsocks.View private void ImportURLItem_Click(object sender, EventArgs e) { - var success = controller.AddServerBySSURL(Clipboard.GetText(TextDataFormat.Text)); - if (success) + if (controller.AskAddServerBySSURL(Clipboard.GetText(TextDataFormat.Text))) { ShowConfigForm(); } From 3652e7f33b8767f92634ce02e0199b65e620aacf Mon Sep 17 00:00:00 2001 From: database64128 Date: Sun, 19 Apr 2020 15:01:38 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=A7=B9=20Minor=20cleanup=20of=20Shado?= =?UTF-8?q?wsocks.Controller.ProtocolHandler.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/System/ProtocolHandler.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/shadowsocks-csharp/Controller/System/ProtocolHandler.cs b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs index e7cf68da..2a0112cb 100644 --- a/shadowsocks-csharp/Controller/System/ProtocolHandler.cs +++ b/shadowsocks-csharp/Controller/System/ProtocolHandler.cs @@ -12,6 +12,8 @@ namespace Shadowsocks.Controller { static class ProtocolHandler { + const string ssURLRegKey = @"SOFTWARE\Classes\ss"; + private static Logger logger = LogManager.GetCurrentClassLogger(); // Don't use Application.ExecutablePath @@ -22,12 +24,13 @@ namespace Shadowsocks.Controller public static bool Set(bool enabled) { RegistryKey ssURLAssociation = null; + try { - ssURLAssociation = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Classes\ss", RegistryKeyPermissionCheck.ReadWriteSubTree); + ssURLAssociation = Registry.CurrentUser.CreateSubKey(ssURLRegKey, RegistryKeyPermissionCheck.ReadWriteSubTree); if (ssURLAssociation == null) { - logger.Error(@"Failed to create HKCU\SOFTWARE\Classes\ss"); + logger.Error(@"Failed to create HKCU\SOFTWARE\Classes\ss to register ss:// association."); return false; } if (enabled) @@ -40,7 +43,7 @@ namespace Shadowsocks.Controller } else { - Registry.CurrentUser.DeleteSubKeyTree(@"SOFTWARE\Classes\ss"); + Registry.CurrentUser.DeleteSubKeyTree(ssURLRegKey); logger.Info(@"Successfully removed ss:// association."); } return true; @@ -70,7 +73,7 @@ namespace Shadowsocks.Controller RegistryKey ssURLAssociation = null; try { - ssURLAssociation = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Classes\ss", true); + ssURLAssociation = Registry.CurrentUser.OpenSubKey(ssURLRegKey, true); if (ssURLAssociation == null) { //logger.Info(@"ss:// links not associated."); From 4bd33db1aedbeaba0c6b5756e236ca597dbc54b7 Mon Sep 17 00:00:00 2001 From: database64128 Date: Sun, 19 Apr 2020 17:55:46 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=94=8D=20Renamed=20to=20NamedPipeServ?= =?UTF-8?q?er=20for=20clarity.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/{PipeServer.cs => NamedPipeServer.cs} | 3 +-- shadowsocks-csharp/Program.cs | 6 +++--- shadowsocks-csharp/shadowsocks-csharp.csproj | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) rename shadowsocks-csharp/Controller/Service/{PipeServer.cs => NamedPipeServer.cs} (97%) diff --git a/shadowsocks-csharp/Controller/Service/PipeServer.cs b/shadowsocks-csharp/Controller/Service/NamedPipeServer.cs similarity index 97% rename from shadowsocks-csharp/Controller/Service/PipeServer.cs rename to shadowsocks-csharp/Controller/Service/NamedPipeServer.cs index fd535b48..23689231 100644 --- a/shadowsocks-csharp/Controller/Service/PipeServer.cs +++ b/shadowsocks-csharp/Controller/Service/NamedPipeServer.cs @@ -16,8 +16,7 @@ namespace Shadowsocks.Controller } } - - internal class PipeServer + internal class NamedPipeServer { public event EventHandler AddUrlRequested; public async void Run(string path) diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 653ee448..3f181105 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -148,9 +148,9 @@ namespace Shadowsocks HotKeys.Init(MainController); MainController.Start(); - PipeServer pipeServer = new PipeServer(); - Task.Run(() => pipeServer.Run(pipename)); - pipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); + NamedPipeServer namedPipeServer = new NamedPipeServer(); + Task.Run(() => namedPipeServer.Run(pipename)); + namedPipeServer.AddUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); if (!addedUrl.IsNullOrEmpty()) { MainController.AskAddServerBySSURL(addedUrl); diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 553573dc..978e58d3 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -113,8 +113,8 @@ - - + +