From 3724028af8544d51580feff27ea0fa9d480959ce Mon Sep 17 00:00:00 2001 From: ProxySU Date: Mon, 12 Oct 2020 19:00:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ProxySU/MainWindow.xaml | 2 +- ProxySU/MainWindow.xaml.cs | 6352 ++++++++--------------- ProxySU/Properties/AssemblyInfo.cs | 4 +- ProxySU/Translations/ProxySU.en-US.xaml | 9 +- ProxySU/Translations/ProxySU.zh-CN.xaml | 9 +- ProxySU/Translations/ProxySU.zh-TW.xaml | 9 +- ProxySU/bin/Beta/Beta.zip | Bin 583343 -> 584092 bytes 7 files changed, 2107 insertions(+), 4278 deletions(-) diff --git a/ProxySU/MainWindow.xaml b/ProxySU/MainWindow.xaml index c0dd46b..b5b1ab7 100644 --- a/ProxySU/MainWindow.xaml +++ b/ProxySU/MainWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ProxySU" mc:Ignorable="d" - Title="ProxySU - v2.4.1" Height="675" Width="650"> + Title="ProxySU - v2.4.3" Height="675" Width="650"> diff --git a/ProxySU/MainWindow.xaml.cs b/ProxySU/MainWindow.xaml.cs index ab9d9f0..cbe0e72 100644 --- a/ProxySU/MainWindow.xaml.cs +++ b/ProxySU/MainWindow.xaml.cs @@ -55,8 +55,13 @@ namespace ProxySU //public static ConnectionInfo ConnectionInfo; public static string proxyType = "V2Ray"; //代理类型标识: V2Ray\TrojanGo\Trojan\NaiveProxy static bool testDomain = false; //设置标识--域名是否需要检测解析,初始化为不需要 + bool functionResult = true; //标示功能函数是否执行状态(true无错误发生/false有错误发生) static string sshShellCommand; //定义保存执行的命令 + static string currentStatus; //定议保存要显示的状态 static string currentShellCommandResult; //定义Shell命令执行结果保存变量 + static bool getApt = false; //判断系统软件管理,下同 + static bool getDnf = false; + static bool getYum = false; static string sshCmdUpdate; //保存软件安装所用更新软件库命令 static string sshCmdInstall; //保存软件安装所用命令格式 static int randomCaddyListenPort = 8800; //Caddy做伪装网站所监听的端口,随机10001-60000 @@ -131,7 +136,7 @@ namespace ProxySU thread.Start(); } - #region 端口数字防错代码,密钥选择代码 检测新版本代码 + #region 检测新版本代码 //检测ProxySU新版本 private void TestLatestVersionProxySU(TextBlock TextBlockLastVersionProxySU,TextBlock TextBlockNewVersionReminder,Button ButtonUpgradeProxySU) @@ -280,6 +285,9 @@ namespace ProxySU ButtonUpgradeProxySU.Visibility = Visibility.Visible; } + #endregion + + #region 安装过程信息显示 端口数字防错代码,密钥选择代码 //更新状态条显示 Action updateAction = new Action(UpdateTextBlock); @@ -328,6 +336,7 @@ namespace ProxySU textBoxName.Text = textBoxName.Text + currentResult + Environment.NewLine; textBoxName.ScrollToEnd(); } + //结尾不添加换行符 Action updateMonitorActionNoWrap = new Action(UpdateTextBoxNoWrap); private static void UpdateTextBoxNoWrap(TextBox textBoxName, string currentResult) @@ -341,6 +350,7 @@ namespace ProxySU { Application.Current.Shutdown(); } + // private static readonly Regex _regex = new Regex("[^0-9]+"); //检测数字输入 @@ -350,14 +360,24 @@ namespace ProxySU e.Handled = regex.IsMatch(e.Text); } + //检测字符串是否只由数字组成 + private bool IsOnlyNumber(string value) + { + value = value.Trim(); + Regex r = new Regex(@"^[0-9]+$"); + return r.Match(value).Success; + } + + //端口输入框是否可使用粘贴命令 private void TextBoxPort_PreviewExecuted(object sender, ExecutedRoutedEventArgs e) { if (e.Command == ApplicationCommands.Paste) { - e.Handled = true; + e.Handled = false;//true为不能使用粘贴命令,false为可以使用粘贴命令 } } + //打开证书浏览 private void ButtonOpenFileDialog_Click(object sender, RoutedEventArgs e) { var openFileDialog = new Microsoft.Win32.OpenFileDialog() @@ -532,7 +552,7 @@ namespace ProxySU { ConnectionInfo connectionInfo; - #region 检测输入的内空是否有错,并读取内容 + #region 检测输入的内容是否有错,并读取内容 if (string.IsNullOrEmpty(TextBoxHost.Text) == true || string.IsNullOrEmpty(TextBoxPort.Text) == true || string.IsNullOrEmpty(TextBoxUserName.Text) == true) { //******"主机地址、主机端口、用户名为必填项,不能为空"****** @@ -541,7 +561,20 @@ namespace ProxySU return connectionInfo = null; } string sshHostName = TextBoxHost.Text.ToString(); - int sshPort = int.Parse(TextBoxPort.Text); + int sshPort = 22; + + if (IsOnlyNumber(TextBoxPort.Text) == true) + { + TextBoxPort.Text = TextBoxPort.Text.Trim(); + sshPort = int.Parse(TextBoxPort.Text); + } + else + { + //******"连接端口含有非数字字符!"****** + MessageBox.Show("Host Port" + Application.Current.FindResource("MessageBoxShow_ErrorHostPortErr").ToString()); + return connectionInfo = null; + } + string sshUser = TextBoxUserName.Text.ToString(); if (RadioButtonPasswordLogin.IsChecked == true && string.IsNullOrEmpty(PasswordBoxHostPassword.Password) == true) @@ -586,7 +619,20 @@ namespace ProxySU return connectionInfo = null; } string sshProxyHost = TextBoxProxyHost.Text.ToString(); - int sshProxyPort = int.Parse(TextBoxProxyPort.Text.ToString()); + + int sshProxyPort = 1080; + if (IsOnlyNumber(TextBoxProxyPort.Text) == true) + { + TextBoxProxyPort.Text = TextBoxProxyPort.Text.Trim(); + sshProxyPort = int.Parse(TextBoxProxyPort.Text); + } + else + { + //******"连接端口含有非数字字符!"****** + MessageBox.Show("Proxy Port" + Application.Current.FindResource("MessageBoxShow_ErrorHostPortErr").ToString()); + return connectionInfo = null; + } + if (RadioButtonNoProxy.IsChecked==false && RadiobuttonProxyYesLogin.IsChecked == true && (string.IsNullOrEmpty(TextBoxProxyUserName.Text) == true || string.IsNullOrEmpty(PasswordBoxProxyPassword.Password) == true)) { //****** "如果代理需要登录,则代理登录的用户名与密码不能为空!" ****** @@ -945,7 +991,7 @@ namespace ProxySU if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == true) { //******"请先选择配置模板!"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ChooseTemplate").ToString()); + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ChooseTemplate").ToString()); return; } else if (String.Equals(ReceiveConfigurationParameters[0], "TCP") == true @@ -978,25 +1024,29 @@ namespace ProxySU //Thread thread //SetUpProgressBarProcessing(0); //重置安装进度 installationDegree = 0; - Thread thread = new Thread(() => StartSetUpV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); + TextBoxMonitorCommandResults.Text = ""; + //Thread thread = new Thread(() => StartSetUpV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); + Thread thread = new Thread(() => StartSetUpV2ray(connectionInfo)); + thread.SetApartmentState(ApartmentState.STA); thread.Start(); - // Task task = new Task(() => StartSetUpRemoteHost(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); - //task.Start(); + } //登录远程主机布署V2ray程序 - private void StartSetUpV2ray(ConnectionInfo connectionInfo,TextBlock textBlockName, ProgressBar progressBar) + + private void StartSetUpV2ray(ConnectionInfo connectionInfo) { - + functionResult = true; + getApt = false; + getDnf = false; + getYum = false; //******"正在登录远程主机......"****** SetUpProgressBarProcessing(1); - string currentStatus = Application.Current.FindResource("DisplayInstallInfo_Login").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + currentStatus = Application.Current.FindResource("DisplayInstallInfo_Login").ToString(); + MainWindowsShowInfo(currentStatus); + try { #region 主机指纹,暂未启用 @@ -1006,7 +1056,6 @@ namespace ProxySU // }; #endregion using (var client = new SshClient(connectionInfo)) - { #region ssh登录验证主机指纹代码块,暂未启用 // client.HostKeyReceived += (sender, e) => @@ -1034,963 +1083,54 @@ namespace ProxySU { //******"主机登录成功"****** SetUpProgressBarProcessing(3); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginSuccessful").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果在监视窗口 - //Thread.Sleep(1000); - + currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginSuccessful").ToString(); + MainWindowsShowInfo(currentStatus); //Thread.Sleep(1000); } - //******"检测是否运行在root权限下..."******01 - SetUpProgressBarProcessing(5); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootPermission").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + //检测root权限 5--7 + functionResult = RootAuthorityDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"id -u"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //检测是否已安装代理 8--10 + functionResult = SoftInstalledIsNoYes(client, "v2ray", @"/usr/local/bin/v2ray"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - string testRootAuthority = currentShellCommandResult; - if (testRootAuthority.Equals("0\n") == false) - { - //******"请使用具有root权限的账户登录主机!!"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorRootPermission").ToString()); - client.Disconnect(); - return; - } - else - { - //******"检测结果:OK!"******02 - SetUpProgressBarProcessing(8); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } + //检测系统是否符合安装要求 11--30 + //检测关闭Selinux及系统组件是否齐全(apt/yum/dnf/systemctl) + //安装依赖软件,检测端口,防火墙开启端口 + functionResult = ShutDownSelinuxAndSysComponentsDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //******"检测系统是否已经安装V2ray......"******03 - SetUpProgressBarProcessing(10); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestExistSoft").ToString() + "V2ray......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + //检测校对时间 31--33 + functionResult = CheckProofreadingTime(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"find / -name v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string resultCmdTestV2rayInstalled = currentShellCommandResult; - if (resultCmdTestV2rayInstalled.Contains("/usr/bin/v2ray") == true || resultCmdTestV2rayInstalled.Contains("/usr/local/bin/v2ray") == true) - { - //******"远程主机已安装V2ray,是否强制重新安装?"****** - string messageShow = Application.Current.FindResource("MessageBoxShow_ExistedSoft").ToString() + - "V2Ray" + - Application.Current.FindResource("MessageBoxShow_ForceInstallSoft").ToString(); - MessageBoxResult messageBoxResult = MessageBox.Show(messageShow, "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult==MessageBoxResult.No) - { - //******"安装取消,退出"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstallationCanceledExit").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - else - { - //******"已选择强制安装V2Ray!"******04 - SetUpProgressBarProcessing(12); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ForceInstallSoft").ToString() + "V2Ray!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - } - } - else - { - //******"检测结果:未安装V2Ray!"******04 - SetUpProgressBarProcessing(12); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_NoInstalledSoft").ToString() + "V2Ray!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //******"检测系统是否符合安装要求......"******05 - SetUpProgressBarProcessing(14); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_CheckSystemRequirements").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"uname -r"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string result = currentShellCommandResult; - string[] linuxKernelVerStr= result.Split('-'); - bool detectResult = DetectKernelVersion(linuxKernelVerStr[0]); - if (detectResult == false) - { - //******$"当前系统内核版本为{linuxKernelVerStr[0]},V2ray要求内核为2.6.23及以上。请升级内核再安装!"****** - MessageBox.Show( - Application.Current.FindResource("MessageBoxShow_CurrentKernelVersion").ToString() + - $"{linuxKernelVerStr[0]}" + - Application.Current.FindResource("MessageBoxShow_RequiredKernelVersionExplain").ToString() - ); - //******"系统内核版本不符合要求,安装失败!!"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_KernelVersionNotMatch").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - - //检测系统是否支持yum 或 apt-get或zypper,且支持Systemd - //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真, - - sshShellCommand = @"command -v apt"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getApt = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v dnf"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getDnf = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v yum"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getYum = String.IsNullOrEmpty(currentShellCommandResult); - - SetUpProgressBarProcessing(16); - - sshShellCommand = @"command -v zypper"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getZypper = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v systemctl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getSystemd = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getGetenforce = String.IsNullOrEmpty(currentShellCommandResult); - - - //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 - //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 - if ((getApt && getDnf && getYum && getZypper) || getSystemd) - { - //******"系统缺乏必要的安装组件如:apt||dnf||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_MissingSystemComponents").ToString()); - - //******"系统环境不满足要求,安装失败!!"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - else - { - //******"检测结果:OK!"******06 - SetUpProgressBarProcessing(18); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SystemRequirementsOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //设置安装软件所用的命令格式 - if (getApt == false) - { - sshCmdUpdate = @"apt -qq update"; - sshCmdInstall = @"apt -y -qq install "; - } - else if (getDnf == false) - { - sshCmdUpdate = @"dnf -q makecache"; - sshCmdInstall = @"dnf -y -q install "; - } - else if (getYum == false) - { - sshCmdUpdate = @"yum -q makecache"; - sshCmdInstall = @"yum -y -q install "; - } - else if (getZypper == false) - { - sshCmdUpdate = @"zypper ref"; - sshCmdInstall = @"zypper -y install "; - } - - //判断是否启用了SELinux,如果启用了,并且工作在Enforcing模式下,则改为Permissive模式 - if (getGetenforce == false) - { - sshShellCommand = @"getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string testSELinux = currentShellCommandResult; - - if (testSELinux.Contains("Enforcing") == true) - { - //******"检测到系统启用SELinux,且工作在严格模式下,需改为宽松模式!修改中......"******07 - SetUpProgressBarProcessing(20); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableSELinux").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"setenforce 0"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //******"修改完毕!"******08 - SetUpProgressBarProcessing(22); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SELinuxModifyOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - } - //在相应系统内安装curl(如果没有安装curl)--此为依赖软件 - if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}curl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //******"校对时间......"******09 - SetUpProgressBarProcessing(24); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ProofreadingTime").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //获取远程主机的时间戳 - long timeStampVPS = Convert.ToInt64(client.RunCommand("date +%s").Result.ToString()); - - //获取本地时间戳 - TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0); - long timeStampLocal = Convert.ToInt64(ts.TotalSeconds); - if (Math.Abs(timeStampLocal - timeStampVPS) >= 90) - { - //******"本地时间与远程主机时间相差超过限制(90秒),请先用 '系统工具-->时间校对' 校对时间后再设置"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_TimeError").ToString()); - //"时间较对失败......" - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TimeError").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - //******"时间差符合要求,OK!"******10 - SetUpProgressBarProcessing(27); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TimeOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - //如果使用是WebSocket + TLS + Web/http2/Http2Web/tcp_TLS/WebSocket_TLS模式,需要检测域名解析是否正确 + //检测域名解析是否正确 34---36 if (testDomain == true) { - //****** "正在检测域名是否解析到当前VPS的IP上......" ******11 - SetUpProgressBarProcessing(28); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestDomainResolve").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"curl -4 ip.sb"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string nativeIp = currentShellCommandResult; - - sshShellCommand = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string resultTestDomainCmd = currentShellCommandResult; - - if (String.Equals(nativeIp, resultTestDomainCmd) == true) - { - //****** "解析正确!OK!" ******12 - SetUpProgressBarProcessing(32); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DomainResolveOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "域名未能正确解析到当前VPS的IP上!安装失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorDomainResolve").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //****** "域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!" ****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorDomainResolve").ToString()); - client.Disconnect(); - return; - } - - //检测是否安装lsof - if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}lsof"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "检测端口占用情况......" ******13 - SetUpProgressBarProcessing(34); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestPortUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"lsof -n -P -i :80 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort80 = currentShellCommandResult; - - sshShellCommand = @"lsof -n -P -i :443 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort443 = currentShellCommandResult; - - - if (String.IsNullOrEmpty(testPort80) == false || String.IsNullOrEmpty(testPort443) == false) - { - //****** "80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?" ****** - MessageBoxResult dialogResult = MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorPortUsed").ToString(), "Stop application", MessageBoxButton.YesNo); - if (dialogResult == MessageBoxResult.No) - { - //****** "端口被占用,安装失败......" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorPortUsedFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - //****** "正在释放80/443端口......" ******14 - SetUpProgressBarProcessing(37); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - if (String.IsNullOrEmpty(testPort443) == false) - { - string[] cmdResultArry443 = testPort443.Split(' '); - sshShellCommand = $"systemctl stop {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry443[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - if (String.IsNullOrEmpty(testPort80) == false) - { - string[] cmdResultArry80 = testPort80.Split(' '); - sshShellCommand = $"systemctl stop {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry80[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "80/443端口释放完毕!" ******15 - SetUpProgressBarProcessing(39); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "检测结果:未被占用!" ******16 - SetUpProgressBarProcessing(41); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_PortNotUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - } - //****** "系统环境检测完毕,符合安装要求,开始布署......" ******17 - SetUpProgressBarProcessing(42); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //****** "开启防火墙相应端口......" ******18 - SetUpProgressBarProcessing(43); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_OpenFireWallPort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string openFireWallPort = ReceiveConfigurationParameters[1]; - if (String.IsNullOrEmpty(client.RunCommand("command -v firewall-cmd").Result) == false) - { - if (String.Equals(openFireWallPort, "443")) - { - sshShellCommand = @"firewall-cmd --zone=public --add-port=80/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"firewall-cmd --zone=public --add-port=443/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | firewall-cmd --reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - } - else - { - sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/udp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | firewall-cmd --reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - } - if (String.IsNullOrEmpty(client.RunCommand("command -v ufw").Result) == false) - { - if (String.Equals(openFireWallPort, "443")) - { - sshShellCommand = @"ufw allow 80"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"ufw allow 443"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | ufw reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - sshShellCommand = $"ufw allow {openFireWallPort}/tcp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"ufw allow {openFireWallPort}/udp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | ufw reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - } - //****** "系统环境检测完毕,符合安装要求,开始布署......" ******18-1 - SetUpProgressBarProcessing(45); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - //下载官方安装脚本安装 - //****** "正在安装V2Ray......" ******19 - SetUpProgressBarProcessing(46); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "V2Ray......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"curl -o /tmp/go.sh https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | bash /tmp/go.sh -f"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"rm -f /tmp/go.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"find / -name v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string installResult = currentShellCommandResult; - - if (!installResult.Contains("/usr/local/bin/v2ray")) - { - //****** "安装失败,官方脚本运行出错!" ****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString()); - //****** "安装失败,官方脚本运行出错!" ****** - currentStatus = Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - client.Disconnect(); - return; - } - else - { - //****** "V2ray安装成功!" ******20 - SetUpProgressBarProcessing(50); - currentStatus = "V2ray" + Application.Current.FindResource("DisplayInstallInfo_SoftInstallSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"systemctl enable v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + functionResult = DomainResolutionCurrentIPDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } } - sshShellCommand = @"mv /usr/local/etc/v2ray/config.json /usr/local/etc/v2ray/config.json.1"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //下载安装脚本安装 37--40 + functionResult = V2RayInstallScript(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //****** "上传配置文件......" ******21 - SetUpProgressBarProcessing(53); + //程序是否安装成功检测 41--43 + functionResult = SoftInstalledSuccessOrFail(client, "v2ray", @"/usr/local/bin/v2ray"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + + //生成服务端配置 44--46 + functionResult = GenerateServerConfigurationV2Ray(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + + //****** "上传配置文件......" ****** 47--50 currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadSoftConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - #region 生成服务端配置 - - //读取配置文件各个模块 - string logConfigJson = @"TemplateConfg\v2ray\server\00_log\00_log.json"; - string apiConfigJson = @"TemplateConfg\v2ray\server\01_api\01_api.json"; - string dnsConfigJson = @"TemplateConfg\v2ray\server\02_dns\02_dns.json"; - string routingConfigJson = @"TemplateConfg\v2ray\server\03_routing\03_routing.json"; - string policyConfigJson = @"TemplateConfg\v2ray\server\04_policy\04_policy.json"; - string inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\05_inbounds.json"; - string outboundsConfigJson = @"TemplateConfg\v2ray\server\06_outbounds\06_outbounds.json"; - string transportConfigJson = @"TemplateConfg\v2ray\server\07_transport\07_transport.json"; - string statsConfigJson = @"TemplateConfg\v2ray\server\08_stats\08_stats.json"; - string reverseConfigJson = @"TemplateConfg\v2ray\server\09_reverse\09_reverse.json"; - string baseConfigJson = @"TemplateConfg\v2ray\base.json"; + MainWindowsShowInfo(currentStatus); string serverRemoteConfig = @"/usr/local/etc/v2ray/config.json"; - - //配置文件模块合成 - using (StreamReader reader = File.OpenText(baseConfigJson)) - { - JObject serverJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); - //读取"log" - using (StreamReader readerJson = File.OpenText(logConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["log"] = jObjectJson["log"]; - } - //读取"api" - using (StreamReader readerJson = File.OpenText(apiConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["api"] = jObjectJson["api"]; - } - //读取"dns" - using (StreamReader readerJson = File.OpenText(dnsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["dns"] = jObjectJson["dns"]; - } - //读取"routing" - using (StreamReader readerJson = File.OpenText(routingConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["routing"] = jObjectJson["routing"]; - } - //读取"policy" - using (StreamReader readerJson = File.OpenText(policyConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["policy"] = jObjectJson["policy"]; - } - //读取"inbounds" - using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["inbounds"] = jObjectJson["inbounds"]; - } - //读取"outbounds" - using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["outbounds"] = jObjectJson["outbounds"]; - } - //读取"transport" - using (StreamReader readerJson = File.OpenText(transportConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["transport"] = jObjectJson["transport"]; - } - //读取"stats" - using (StreamReader readerJson = File.OpenText(statsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["stats"] = jObjectJson["stats"]; - } - //读取"reverse" - using (StreamReader readerJson = File.OpenText(reverseConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - serverJson["reverse"] = jObjectJson["reverse"]; - } - - //依据安装模式读取相应模板 - if (String.Equals(ReceiveConfigurationParameters[0], "TCP") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_http_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_TLS_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcpTLSselfSigned_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_tcp_xtls_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_tcp_tls_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_ws_tls_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_http2_tls_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_vmess_xtls_tcp_websocket_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\webSocket_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocket_TLS_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocketTLS_selfSigned_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocketTLSWeb_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\http2_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\Http2Web_server_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\Http2selfSigned_server_config.json"; - } - //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\mkcp_server_config.json"; - } - - // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("Quic") == true) - { - inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\quic_server_config.json"; - } - - //读取"inbounds" - using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) - { - JObject jObjectJsonTmp = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - var jObjectJson = (dynamic)jObjectJsonTmp; - - //Padavan路由固件服务端设置(因为客户端分流有问题所以在服务端弥补)加上后会影响一定的速度 - - //string sniffingAddServer = @"TemplateConfg\v2ray\server\05_inbounds\00_padavan_router.json"; - //using (StreamReader readerSniffingJson = File.OpenText(sniffingAddServer)) - //{ - // JObject jObjectSniffingJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerSniffingJson)); - // jObjectJson["inbounds"][0]["sniffing"] = jObjectSniffingJson["sniffing"]; - //} - - //设置uuid - jObjectJson["inbounds"][0]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; - - //除WebSocketTLSWeb/http2Web/VLESS+WebSocket+TLS+Web/VLESS+http2+TLS+Web模式外设置监听端口 - if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == false - && String.Equals(ReceiveConfigurationParameters[0], "http2Web") == false - && String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == false - && String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == false) - { - jObjectJson["inbounds"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - } - - //设置VLESS协议的回落端口,指向Caddy - if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) - { - //设置Caddy随机监听的端口 - randomCaddyListenPort = GetRandomPort(); - - //指向Caddy监听的随机端口 - jObjectJson["inbounds"][0]["settings"]["fallbacks"][0]["dest"] = randomCaddyListenPort; - } - - // - if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) - { - //设置其他模式的UUID - jObjectJson["inbounds"][1]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; - jObjectJson["inbounds"][2]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; - jObjectJson["inbounds"][3]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; - - //设置Vless回落与分流的Path - jObjectJson["inbounds"][0]["settings"]["fallbacks"][1]["path"] = ReceiveConfigurationParameters[3]; - jObjectJson["inbounds"][0]["settings"]["fallbacks"][2]["path"] = ReceiveConfigurationParameters[9]; - jObjectJson["inbounds"][0]["settings"]["fallbacks"][3]["path"] = ReceiveConfigurationParameters[6]; - - //设置Vless ws Path - jObjectJson["inbounds"][1]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; - //设置Vmess tcp Path - jObjectJson["inbounds"][2]["streamSettings"]["tcpSettings"]["header"]["request"]["path"][0] = ReceiveConfigurationParameters[9]; - //设置Vmess ws Path - jObjectJson["inbounds"][3]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; - - } - - //TLS自签证书/WebSocketTLS(自签证书)/http2自签证书模式下,使用v2ctl 生成自签证书 - if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) - { - string selfSignedCa = client.RunCommand("/usr/local/bin/v2ctl cert --ca").Result; - JObject selfSignedCaJObject = JObject.Parse(selfSignedCa); - jObjectJson["inbounds"][0]["streamSettings"]["tlsSettings"]["certificates"][0] = selfSignedCaJObject; - } - - //如果是WebSocketTLSWeb/WebSocketTLS/WebSocketTLS(自签证书)/VLESS+WebSocket+TLS+Web模式,则设置路径 - if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true - || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb")==true) - { - jObjectJson["inbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; - } - - //如果是Http2/http2Web/http2自签/VLESS+http2+TLS+Web模式下,设置路径 - if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true - || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - jObjectJson["inbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[6]; - } - - //如果是Http2+Web/VLESS+http2+TLS+Web模式下,设置host - if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - jObjectJson["inbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; - } - - //mkcp模式下,设置伪装类型 - if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) - { - jObjectJson["inbounds"][0]["streamSettings"]["kcpSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[6]) == false) - { - jObjectJson["inbounds"][0]["streamSettings"]["kcpSettings"]["seed"] = ReceiveConfigurationParameters[6]; - } - } - - //quic模式下设置伪装类型及密钥 - if (ReceiveConfigurationParameters[0].Contains("Quic") == true) - { - jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; - jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["security"] = ReceiveConfigurationParameters[3]; - - if (String.Equals(ReceiveConfigurationParameters[3],"none") == true) - { - ReceiveConfigurationParameters[6] = ""; - } - jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["key"] = ReceiveConfigurationParameters[6]; - } - - serverJson["inbounds"] = jObjectJson["inbounds"]; - } - - using (StreamWriter sw = new StreamWriter(@"config.json")) - { - sw.Write(serverJson.ToString()); - } - } - //"/usr/local/etc/v2ray/config.json"; UploadConfig(connectionInfo, @"config.json", serverRemoteConfig); - File.Delete(@"config.json"); - - #endregion - - #region acme.sh安装 + SetUpProgressBarProcessing(50); //如果使用http2/WebSocketTLS/tcpTLS/VlessTcpTlsWeb/VLESS+TCP+XTLS+Web模式,先要安装acme.sh,申请证书 if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true @@ -2000,348 +1140,43 @@ namespace ProxySU || String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) { - //****** "正在安装acme.sh......" ******22 - SetUpProgressBarProcessing(55); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallAcmeSh").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //安装acme.sh与申请证书 51--57 + functionResult = AcmeShInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //Thread.Sleep(1000); - - //安装所依赖的软件 - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}socat"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //解决搬瓦工CentOS缺少问题 - sshShellCommand = $"{sshCmdInstall}automake autoconf libtool"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - sshShellCommand = @"curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("Install success") == true) - { - //****** "acme.sh安装成功!" ******23 - SetUpProgressBarProcessing(58); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_AcmeShInstallSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "acme.sh安装失败!原因未知,请向开发者提问!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorAcmeShInstallFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - return; - } - - sshShellCommand = @"cd ~/.acme.sh/"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"alias acme.sh=~/.acme.sh/acme.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //****** "申请域名证书......" ******24 - SetUpProgressBarProcessing(60); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartApplyCert").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = $"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("Cert success") == true) - { - //****** "证书申请成功!" ******25 - SetUpProgressBarProcessing(63); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "证书申请失败!原因未知,请向开发者提问!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - return; - } - //****** "安装证书到V2ray......" ******26 - SetUpProgressBarProcessing(65); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoft").ToString() + "V2ray......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"mkdir -p /usr/local/etc/v2ray/ssl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/v2ray/ssl/v2ray_ssl.crt --keypath /usr/local/etc/v2ray/ssl/v2ray_ssl.key --capath /usr/local/etc/v2ray/ssl/v2ray_ssl.crt --reloadcmd \"systemctl restart v2ray\""; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"if [ ! -f ""/usr/local/etc/v2ray/ssl/v2ray_ssl.key"" ]; then echo ""0""; else echo ""1""; fi | head -n 1"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("1") == true) - { - //****** "证书成功安装到V2ray!" ******27 - SetUpProgressBarProcessing(68); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftOK").ToString() + "V2Ray!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - //****** "证书安装到V2ray失败,原因未知,可以向开发者提问!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftFail").ToString() + - "V2Ray" + - Application.Current.FindResource("DisplayInstallInfo_InstallCertFailAsk").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - return; - } - - //设置私钥权限 - sshShellCommand = @"chmod 644 /usr/local/etc/v2ray/ssl/v2ray_ssl.key"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //安装证书到V2Ray 58--60 + functionResult = CertInstallToV2ray(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } } - #endregion - #region Caddy安装 + #region Caddy安装 61--70 //如果是VLESS+TCP+XTLS+Web/VLESS+TCP+TLS+Web/VLESS+WebSocket+TLS+Web/VLESS+http2+TLS+Web/WebSocket+TLS+Web/http2Web模式,需要安装Caddy if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true - || String.Equals(ReceiveConfigurationParameters[0],"WebSocketTLS2Web") ==true + || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) { - //****** "安装Caddy......" ******28 - SetUpProgressBarProcessing(70); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallCaddy").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //安装Caddy - //为假则表示系统有相应的组件。 - if (getApt == false) - { - - sshShellCommand = @"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt install -y apt-transport-https"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt -qq update"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt -y -qq install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else if (getDnf == false) - { - - sshShellCommand = @"dnf install 'dnf-command(copr)' -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"dnf copr enable @caddy/caddy -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //sshShellCommand = @"dnf -q makecache"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //安装Caddy 61--66 + functionResult = CaddyInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"dnf -y -q install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + #region 上传Caddy配置文件 67--70 - } - else if (getYum == false) - { - - sshShellCommand = @"yum install yum-plugin-copr -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yum copr enable @caddy/caddy -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //sshShellCommand = @"yum -q makecache"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yum -y -q install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - sshShellCommand = @"find / -name caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - installResult = currentShellCommandResult; - - if (!installResult.Contains("/usr/bin/caddy")) - { - //****** "安装Caddy失败!" ****** - MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString()); - //****** "安装Caddy失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - client.Disconnect(); - return; - } - //****** "Caddy安装成功!" ******29 - SetUpProgressBarProcessing(75); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstalledCaddyOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"systemctl enable caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //在Caddy 2还未推出2.2.0的正式版之前,先用测试版替代 - if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - //****** "正在为Http2Web模式升级Caddy v2.2.0测试版!" ******30 - SetUpProgressBarProcessing(77); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_UpgradeCaddy").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"curl -o /tmp/caddy.zip https://raw.githubusercontent.com/proxysu/Resources/master/Caddy2/caddy.zip"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | unzip -o /tmp/caddy.zip"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"chmod +x caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"systemctl stop caddy;rm -f /usr/bin/caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"cp /root/caddy /usr/bin/"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"rm -f /tmp/caddy.zip caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "上传Caddy配置文件......" ******31 - SetUpProgressBarProcessing(80); + //******"上传Caddy配置文件"****** + SetUpProgressBarProcessing(67); currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); - //Thread.Sleep(1000); string serverConfig = ""; sshShellCommand = @"mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true || String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true @@ -2359,7 +1194,7 @@ namespace ProxySU { serverConfig = @"TemplateConfg\v2ray\caddy\Http2Web.caddyfile"; } - + string upLoadPath = "/etc/caddy/Caddyfile"; client.RunCommand("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak"); UploadConfig(connectionInfo, serverConfig, upLoadPath); @@ -2370,675 +1205,52 @@ namespace ProxySU string randomCaddyListenPortStr = randomCaddyListenPort.ToString(); sshShellCommand = $"sed -i 's/8800/{randomCaddyListenPortStr}/' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); //设置域名 sshShellCommand = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}/g' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); //设置Path sshShellCommand = $"sed -i 's/##path##/\\{ReceiveConfigurationParameters[6]}/' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); //设置伪装网站 - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7])==false) + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) { sshShellCommand = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); } //****** "Caddy配置文件上传成功,OK!" ******32 - SetUpProgressBarProcessing(85); + SetUpProgressBarProcessing(70); currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfigOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); + #endregion //启动Caddy服务 - //****** "正在启动Caddy......" ******33 - SetUpProgressBarProcessing(87); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyService").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //启动Caddy服务 - sshShellCommand = @"systemctl restart caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - { - //****** "Caddy启动成功!" ******34 - SetUpProgressBarProcessing(88); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Caddy启动失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(1000); - - //****** "正在启动Caddy(第二次尝试)!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecond").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - sshShellCommand = @"systemctl restart caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - { - //****** "Caddy启动成功!" ****** - - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Caddy启动失败(第二次)!退出安装!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecondFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - //****** "Caddy启动失败,原因未知!请向开发者问询!" ****** - MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_CaddyServiceFailedExit").ToString()); - return; - } - } - + functionResult = SoftStartDetect(client, "caddy", @"/usr/bin/caddy"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } } - #endregion //****** "正在启动V2ray......" ******35 - SetUpProgressBarProcessing(90); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoft").ToString() + "V2ray......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //启动V2ray服务 - sshShellCommand = @"systemctl restart v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("/usr/local/bin/v2ray") == true) - { - //****** "V2ray启动成功!" ******36 - SetUpProgressBarProcessing(93); - currentStatus = "V2ray" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "V2ray启动失败!" ****** - currentStatus = "V2ray" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - //****** "正在第二次尝试启动V2ray!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoftSecond").ToString() + "V2ray!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - sshShellCommand = @"systemctl restart v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep v2ray"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("/usr/local/bin/v2ray") == true) - { - //****** "V2ray启动成功!" ****** - currentStatus = "V2ray" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "V2ray启动失败(第二次)!退出安装!" ****** - currentStatus = "V2ray" + Application.Current.FindResource("DisplayInstallInfo_StartSoftSecondFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - //****** "V2Ray启动失败,原因未知!请向开发者问询!" ****** - MessageBox.Show("V2Ray" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFailedExit").ToString()); - return; - } - } - + functionResult = SoftStartDetect(client, "v2ray", @"/usr/local/bin/v2ray"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } //测试BBR条件,若满足提示是否启用 - //****** "BBR测试......" ******37 - SetUpProgressBarProcessing(95); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + functionResult = DetectBBRandEnable(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //Thread.Sleep(1000); - - sshShellCommand = @"uname -r"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string[] linuxKernelVerStrBBR = currentShellCommandResult.Split('-'); - - bool detectResultBBR = DetectKernelVersionBBR(linuxKernelVerStrBBR[0]); - - sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string resultCmdTestBBR = currentShellCommandResult; - //如果内核满足大于等于4.9,且还未启用BBR,则启用BBR - if (detectResultBBR == true && resultCmdTestBBR.Contains("bbr") == false) - { - //****** "正在启用BBR......" ******38 - SetUpProgressBarProcessing(97); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"bash -c 'echo ""net.core.default_qdisc=fq"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"bash -c 'echo ""net.ipv4.tcp_congestion_control=bbr"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"sysctl -p"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("bbr") == true) - { - //****** "BBR启用成功!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBREnabledSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - //****** "系统不满足启用BBR的条件,启用失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - } - else if (resultCmdTestBBR.Contains("bbr") == true) - { - //****** "BBR已经启用了!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRisEnabled").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - //****** "系统不满足启用BBR的条件,启用失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } client.Disconnect();//断开服务器ssh连接 - #region 生成客户端配置 - - //****** "生成客户端配置......" ******39 - SetUpProgressBarProcessing(99); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_GenerateClientConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - logConfigJson = @"TemplateConfg\v2ray\client\00_log\00_log.json"; - apiConfigJson = @"TemplateConfg\v2ray\client\01_api\01_api.json"; - dnsConfigJson = @"TemplateConfg\v2ray\client\02_dns\02_dns.json"; - routingConfigJson = @"TemplateConfg\v2ray\client\03_routing\03_routing.json"; - policyConfigJson = @"TemplateConfg\v2ray\client\04_policy\04_policy.json"; - inboundsConfigJson = @"TemplateConfg\v2ray\client\05_inbounds\05_inbounds.json"; - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\06_outbounds.json"; - transportConfigJson = @"TemplateConfg\v2ray\client\07_transport\07_transport.json"; - statsConfigJson = @"TemplateConfg\v2ray\client\08_stats\08_stats.json"; - reverseConfigJson = @"TemplateConfg\v2ray\client\09_reverse\09_reverse.json"; - baseConfigJson = @"TemplateConfg\v2ray\base.json"; - //Thread.Sleep(1000); - if (!Directory.Exists("v2ray_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory("v2ray_config");//创建该文件夹   - } - - using (StreamReader reader = File.OpenText(baseConfigJson)) - { - JObject clientJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); - //读取"log" - using (StreamReader readerJson = File.OpenText(logConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["log"] = jObjectJson["log"]; - } - //读取"api" - using (StreamReader readerJson = File.OpenText(apiConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["api"] = jObjectJson["api"]; - } - //读取"dns" - using (StreamReader readerJson = File.OpenText(dnsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["dns"] = jObjectJson["dns"]; - } - //读取"routing" - using (StreamReader readerJson = File.OpenText(routingConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["routing"] = jObjectJson["routing"]; - } - //读取"policy" - using (StreamReader readerJson = File.OpenText(policyConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["policy"] = jObjectJson["policy"]; - } - //读取"inbounds" - using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["inbounds"] = jObjectJson["inbounds"]; - } - //读取"outbounds" - using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["outbounds"] = jObjectJson["outbounds"]; - } - //读取"transport" - using (StreamReader readerJson = File.OpenText(transportConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["transport"] = jObjectJson["transport"]; - } - //读取"stats" - using (StreamReader readerJson = File.OpenText(statsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["stats"] = jObjectJson["stats"]; - } - //读取"reverse" - using (StreamReader readerJson = File.OpenText(reverseConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - clientJson["reverse"] = jObjectJson["reverse"]; - } - - //根据不同的安装方案,选择相应的客户端模板 - if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == false) - { - #region 单模式方案 - //根据选择的不同模式,选择相应的配置文件 - if (String.Equals(ReceiveConfigurationParameters[0], "TCP") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_http_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_TLS_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcpTLSselfSigned_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_xtls_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_tls_caddy_cilent_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_ws_tls_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_http2_tls_server_config.json"; - } - - else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\webSocket_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocket_TLS_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLS_selfSigned_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLSWeb_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\http2_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\Http2Web_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\Http2selfSigned_client_config.json"; - } - //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\mkcp_client_config.json"; - } - // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("Quic") == true) - { - outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\quic_client_config.json"; - } - - - //读取"相应模板的outbounds" - using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - - - //设置WebSocket模式下的path - if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true - || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) - { - jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; - } - - //设置http2模式下的path - if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true - || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - jObjectJson["outbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[6]; - } - - //设置http2+TLS+Web/VLESS+http2+TLS+Web模式下的host - if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true - || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) - { - jObjectJson["outbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; - } - - //设置VLESS+TCP+XTLS+Web模式下的serverName - //if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) - //{ - // jObjectJson["outbounds"][0]["streamSettings"]["xtlsSettings"]["serverName"] = ReceiveConfigurationParameters[4]; - //} - - //设置mkcp - if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) - { - jObjectJson["outbounds"][0]["streamSettings"]["kcpSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[6]) == false) - { - jObjectJson["outbounds"][0]["streamSettings"]["kcpSettings"]["seed"] = ReceiveConfigurationParameters[6]; - } - } - - //设置QUIC - if (ReceiveConfigurationParameters[0].Contains("Quic") == true) - { - jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; - jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["security"] = ReceiveConfigurationParameters[3]; - if (String.Equals(ReceiveConfigurationParameters[3], "none") == true) - { - ReceiveConfigurationParameters[6] = ""; - } - jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["key"] = ReceiveConfigurationParameters[6]; - } - - clientJson["outbounds"] = jObjectJson["outbounds"]; - - } - - using (StreamWriter sw = new StreamWriter(@"v2ray_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - - #endregion - - } - else - { - //复合方案所需要的配置文件 - //VLESS over TCP with XTLS模式 - string outboundsConfigJsonVlessXtls = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_xtls_client_config.json"; - using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessXtls)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - - clientJson["outbounds"] = jObjectJson["outbounds"]; - if (!Directory.Exists(@"v2ray_config\vless_tcp_xtls_client_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory(@"v2ray_config\vless_tcp_xtls_client_config");//创建该文件夹   - } - using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_tcp_xtls_client_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - } - - //VLESS over TCP with TLS模式 - string outboundsConfigJsonVlessTcpTls = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_tls_caddy_cilent_config.json"; - using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessTcpTls)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - - clientJson["outbounds"] = jObjectJson["outbounds"]; - if (!Directory.Exists(@"v2ray_config\vless_tcp_tls_client_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory(@"v2ray_config\vless_tcp_tls_client_config");//创建该文件夹   - } - using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_tcp_tls_client_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - } - - //VLESS over WS with TLS 模式 - string outboundsConfigJsonVlessWsTls = @"TemplateConfg\v2ray\client\06_outbounds\vless_ws_tls_client_config.json"; - using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessWsTls)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; - - clientJson["outbounds"] = jObjectJson["outbounds"]; - if (!Directory.Exists(@"v2ray_config\vless_ws_tls_client_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory(@"v2ray_config\vless_ws_tls_client_config");//创建该文件夹   - } - using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_ws_tls_client_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - } - - //VMess over TCP with TLS模式 - string outboundsConfigJsonVmessTcpTls = @"TemplateConfg\v2ray\client\06_outbounds\vmess_tcp_tls_client_config.json"; - using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVmessTcpTls)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - jObjectJson["outbounds"][0]["streamSettings"]["tcpSettings"]["header"]["request"]["path"][0] = ReceiveConfigurationParameters[9]; - - clientJson["outbounds"] = jObjectJson["outbounds"]; - if (!Directory.Exists(@"v2ray_config\vmess_tcp_tls_client_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory(@"v2ray_config\vmess_tcp_tls_client_config");//创建该文件夹   - } - using (StreamWriter sw = new StreamWriter(@"v2ray_config\vmess_tcp_tls_client_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - } - - //VMess over WS with TLS模式 - string outboundsConfigJsonVmessWsTls = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLSWeb_client_config.json"; - using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVmessWsTls)) - { - JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); - - //设置客户端的地址/端口/id - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); - jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; - - clientJson["outbounds"] = jObjectJson["outbounds"]; - if (!Directory.Exists(@"v2ray_config\vmess_ws_tls_client_config"))//如果不存在就创建file文件夹      - { - Directory.CreateDirectory(@"v2ray_config\vmess_ws_tls_client_config");//创建该文件夹   - } - using (StreamWriter sw = new StreamWriter(@"v2ray_config\vmess_ws_tls_client_config\config.json")) - { - sw.Write(clientJson.ToString()); - } - } - - } - } - - #endregion + //生成客户端配置 96--98 + functionResult = GenerateClientConfigurationV2Ray(); //****** "V2Ray安装成功,祝你玩的愉快!!" ******40 SetUpProgressBarProcessing(100); currentStatus = "V2Ray" + Application.Current.FindResource("DisplayInstallInfo_ProxyInstalledOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); + Thread.Sleep(1000); //显示服务端连接参数 @@ -3047,64 +1259,756 @@ namespace ProxySU resultClientInformation.ShowDialog(); return; + } } catch (Exception ex1)//例外处理 - #region 例外处理 { ProcessException(ex1.Message); - #region 旧代码 - //string exceptionMessage = ex1.Message; - //if (exceptionMessage.Contains("连接尝试失败") == true) - //{ - // //****** "请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作!" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginHostOrPort").ToString()); - //} - - //else if (exceptionMessage.Contains("denied (password)") == true) - //{ - // //****** "密码错误或用户名错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginUserOrPassword").ToString()); - //} - //else if (exceptionMessage.Contains("Invalid private key file") == true) - //{ - // //****** "所选密钥文件错误或者格式不对!" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginKey").ToString()); - //} - //else if (exceptionMessage.Contains("denied (publickey)") == true) - //{ - // //****** "使用密钥登录,密钥文件错误或用户名错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginKeyOrUser").ToString()); - //} - //else if (exceptionMessage.Contains("目标计算机积极拒绝") == true) - //{ - // //****** "主机地址错误,如果使用了代理,也可能是连接代理的端口错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginHostOrProxyPort").ToString()); - //} - //else - //{ - // //****** "发生错误" ****** - // MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorLoginOccurred").ToString()); - // MessageBox.Show(exceptionMessage); - //} - #endregion - - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } - #endregion } + #region V2Ray专用调用函数 + + //下载安装脚本安装V2Ray 37--40 + //functionResult = V2RayInstallScript(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool V2RayInstallScript(SshClient client) + { + //****** "系统环境检测完毕,符合安装要求,开始布署......" ******17 + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); + MainWindowsShowInfo(currentStatus); + + //下载官方安装脚本安装 + //****** "正在安装V2Ray......" ******19 + SetUpProgressBarProcessing(37); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "V2Ray......"; + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"curl -o /tmp/go.sh https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | bash /tmp/go.sh -f"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"rm -f /tmp/go.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + SetUpProgressBarProcessing(40); + return true; + } + + //生成V2Ray服务端配置 44--46 + //functionResult = GenerateServerConfiguration(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool GenerateServerConfigurationV2Ray(SshClient client) + { + SetUpProgressBarProcessing(44); + //备份原来的文件 + sshShellCommand = @"mv /usr/local/etc/v2ray/config.json /usr/local/etc/v2ray/config.json.1"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //读取配置文件各个模块 + string logConfigJson = @"TemplateConfg\v2ray\server\00_log\00_log.json"; + string apiConfigJson = @"TemplateConfg\v2ray\server\01_api\01_api.json"; + string dnsConfigJson = @"TemplateConfg\v2ray\server\02_dns\02_dns.json"; + string routingConfigJson = @"TemplateConfg\v2ray\server\03_routing\03_routing.json"; + string policyConfigJson = @"TemplateConfg\v2ray\server\04_policy\04_policy.json"; + string inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\05_inbounds.json"; + string outboundsConfigJson = @"TemplateConfg\v2ray\server\06_outbounds\06_outbounds.json"; + string transportConfigJson = @"TemplateConfg\v2ray\server\07_transport\07_transport.json"; + string statsConfigJson = @"TemplateConfg\v2ray\server\08_stats\08_stats.json"; + string reverseConfigJson = @"TemplateConfg\v2ray\server\09_reverse\09_reverse.json"; + string baseConfigJson = @"TemplateConfg\v2ray\base.json"; + + //配置文件模块合成 + using (StreamReader reader = File.OpenText(baseConfigJson)) + { + JObject serverJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); + //读取"log" + using (StreamReader readerJson = File.OpenText(logConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["log"] = jObjectJson["log"]; + } + //读取"api" + using (StreamReader readerJson = File.OpenText(apiConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["api"] = jObjectJson["api"]; + } + //读取"dns" + using (StreamReader readerJson = File.OpenText(dnsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["dns"] = jObjectJson["dns"]; + } + //读取"routing" + using (StreamReader readerJson = File.OpenText(routingConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["routing"] = jObjectJson["routing"]; + } + //读取"policy" + using (StreamReader readerJson = File.OpenText(policyConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["policy"] = jObjectJson["policy"]; + } + //读取"inbounds" + using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["inbounds"] = jObjectJson["inbounds"]; + } + //读取"outbounds" + using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["outbounds"] = jObjectJson["outbounds"]; + } + //读取"transport" + using (StreamReader readerJson = File.OpenText(transportConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["transport"] = jObjectJson["transport"]; + } + //读取"stats" + using (StreamReader readerJson = File.OpenText(statsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["stats"] = jObjectJson["stats"]; + } + //读取"reverse" + using (StreamReader readerJson = File.OpenText(reverseConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + serverJson["reverse"] = jObjectJson["reverse"]; + } + + //依据安装模式读取相应模板 + if (String.Equals(ReceiveConfigurationParameters[0], "TCP") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_http_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcp_TLS_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\tcpTLSselfSigned_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_tcp_xtls_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_tcp_tls_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_ws_tls_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_http2_tls_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\vless_vmess_xtls_tcp_websocket_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\webSocket_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocket_TLS_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocketTLS_selfSigned_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\WebSocketTLSWeb_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\http2_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\Http2Web_server_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\Http2selfSigned_server_config.json"; + } + //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\mkcp_server_config.json"; + } + + // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("Quic") == true) + { + inboundsConfigJson = @"TemplateConfg\v2ray\server\05_inbounds\quic_server_config.json"; + } + + //读取"inbounds" + using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) + { + JObject jObjectJsonTmp = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + var jObjectJson = (dynamic)jObjectJsonTmp; + + //Padavan路由固件服务端设置(因为客户端分流有问题所以在服务端弥补)加上后会影响一定的速度 + + //string sniffingAddServer = @"TemplateConfg\v2ray\server\05_inbounds\00_padavan_router.json"; + //using (StreamReader readerSniffingJson = File.OpenText(sniffingAddServer)) + //{ + // JObject jObjectSniffingJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerSniffingJson)); + // jObjectJson["inbounds"][0]["sniffing"] = jObjectSniffingJson["sniffing"]; + //} + + //设置uuid + jObjectJson["inbounds"][0]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; + + //除WebSocketTLSWeb/http2Web/VLESS+WebSocket+TLS+Web/VLESS+http2+TLS+Web模式外设置监听端口 + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == false + && String.Equals(ReceiveConfigurationParameters[0], "http2Web") == false + && String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == false + && String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == false) + { + jObjectJson["inbounds"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + } + + //设置VLESS协议的回落端口,指向Caddy + if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) + { + //设置Caddy随机监听的端口 + randomCaddyListenPort = GetRandomPort(); + + //指向Caddy监听的随机端口 + jObjectJson["inbounds"][0]["settings"]["fallbacks"][0]["dest"] = randomCaddyListenPort; + } + + // + if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == true) + { + //设置其他模式的UUID + jObjectJson["inbounds"][1]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; + jObjectJson["inbounds"][2]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; + jObjectJson["inbounds"][3]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; + + //设置Vless回落与分流的Path + jObjectJson["inbounds"][0]["settings"]["fallbacks"][1]["path"] = ReceiveConfigurationParameters[3]; + jObjectJson["inbounds"][0]["settings"]["fallbacks"][2]["path"] = ReceiveConfigurationParameters[9]; + jObjectJson["inbounds"][0]["settings"]["fallbacks"][3]["path"] = ReceiveConfigurationParameters[6]; + + //设置Vless ws Path + jObjectJson["inbounds"][1]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; + //设置Vmess tcp Path + jObjectJson["inbounds"][2]["streamSettings"]["tcpSettings"]["header"]["request"]["path"][0] = ReceiveConfigurationParameters[9]; + //设置Vmess ws Path + jObjectJson["inbounds"][3]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; + + } + + //TLS自签证书/WebSocketTLS(自签证书)/http2自签证书模式下,使用v2ctl 生成自签证书 + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) + { + string selfSignedCa = client.RunCommand("/usr/local/bin/v2ctl cert --ca").Result; + JObject selfSignedCaJObject = JObject.Parse(selfSignedCa); + jObjectJson["inbounds"][0]["streamSettings"]["tlsSettings"]["certificates"][0] = selfSignedCaJObject; + } + + //如果是WebSocketTLSWeb/WebSocketTLS/WebSocketTLS(自签证书)/VLESS+WebSocket+TLS+Web模式,则设置路径 + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true + || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) + { + jObjectJson["inbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; + } + + //如果是Http2/http2Web/http2自签/VLESS+http2+TLS+Web模式下,设置路径 + if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true + || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + jObjectJson["inbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[6]; + } + + //如果是Http2+Web/VLESS+http2+TLS+Web模式下,设置host + if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + jObjectJson["inbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; + } + + //mkcp模式下,设置伪装类型 + if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) + { + jObjectJson["inbounds"][0]["streamSettings"]["kcpSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[6]) == false) + { + jObjectJson["inbounds"][0]["streamSettings"]["kcpSettings"]["seed"] = ReceiveConfigurationParameters[6]; + } + } + + //quic模式下设置伪装类型及密钥 + if (ReceiveConfigurationParameters[0].Contains("Quic") == true) + { + jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; + jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["security"] = ReceiveConfigurationParameters[3]; + + if (String.Equals(ReceiveConfigurationParameters[3], "none") == true) + { + ReceiveConfigurationParameters[6] = ""; + } + jObjectJson["inbounds"][0]["streamSettings"]["quicSettings"]["key"] = ReceiveConfigurationParameters[6]; + } + + serverJson["inbounds"] = jObjectJson["inbounds"]; + } + + using (StreamWriter sw = new StreamWriter(@"config.json")) + { + sw.Write(serverJson.ToString()); + } + } + SetUpProgressBarProcessing(46); + return true; + } + + //安装证书到V2Ray 58--60 + //functionResult = CertInstallToV2ray(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool CertInstallToV2ray(SshClient client) + { + //****** "安装证书到V2ray......" ******26 + SetUpProgressBarProcessing(58); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoft").ToString() + "V2ray......"; + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"mkdir -p /usr/local/etc/v2ray/ssl"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/v2ray/ssl/v2ray_ssl.crt --keypath /usr/local/etc/v2ray/ssl/v2ray_ssl.key --capath /usr/local/etc/v2ray/ssl/v2ray_ssl.crt --reloadcmd \"systemctl restart v2ray\""; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"if [ ! -f ""/usr/local/etc/v2ray/ssl/v2ray_ssl.key"" ]; then echo ""0""; else echo ""1""; fi | head -n 1"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains("1") == true) + { + //****** "证书成功安装到V2ray!" ******27 + SetUpProgressBarProcessing(60); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftOK").ToString() + "V2Ray!"; + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "证书安装到V2ray失败,原因未知,可以向开发者提问!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftFail").ToString() + + "V2Ray" + + Application.Current.FindResource("DisplayInstallInfo_InstallCertFailAsk").ToString(); + MainWindowsShowInfo(currentStatus); + return false; + } + + //设置私钥权限 + sshShellCommand = @"chmod 644 /usr/local/etc/v2ray/ssl/v2ray_ssl.key"; + MainWindowsShowInfo(currentStatus); + return true; + } + + //生成V2Ray客户端配置 96--98 + //functionResult = GenerateClientConfiguration(); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool GenerateClientConfigurationV2Ray() + { + //****** "生成客户端配置......" ******39 + SetUpProgressBarProcessing(96); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_GenerateClientConfig").ToString(); + MainWindowsShowInfo(currentStatus); + + string logConfigJson = @"TemplateConfg\v2ray\client\00_log\00_log.json"; + string apiConfigJson = @"TemplateConfg\v2ray\client\01_api\01_api.json"; + string dnsConfigJson = @"TemplateConfg\v2ray\client\02_dns\02_dns.json"; + string routingConfigJson = @"TemplateConfg\v2ray\client\03_routing\03_routing.json"; + string policyConfigJson = @"TemplateConfg\v2ray\client\04_policy\04_policy.json"; + string inboundsConfigJson = @"TemplateConfg\v2ray\client\05_inbounds\05_inbounds.json"; + string outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\06_outbounds.json"; + string transportConfigJson = @"TemplateConfg\v2ray\client\07_transport\07_transport.json"; + string statsConfigJson = @"TemplateConfg\v2ray\client\08_stats\08_stats.json"; + string reverseConfigJson = @"TemplateConfg\v2ray\client\09_reverse\09_reverse.json"; + string baseConfigJson = @"TemplateConfg\v2ray\base.json"; + //Thread.Sleep(1000); + if (!Directory.Exists("v2ray_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory("v2ray_config");//创建该文件夹   + } + + using (StreamReader reader = File.OpenText(baseConfigJson)) + { + JObject clientJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); + //读取"log" + using (StreamReader readerJson = File.OpenText(logConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["log"] = jObjectJson["log"]; + } + //读取"api" + using (StreamReader readerJson = File.OpenText(apiConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["api"] = jObjectJson["api"]; + } + //读取"dns" + using (StreamReader readerJson = File.OpenText(dnsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["dns"] = jObjectJson["dns"]; + } + //读取"routing" + using (StreamReader readerJson = File.OpenText(routingConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["routing"] = jObjectJson["routing"]; + } + //读取"policy" + using (StreamReader readerJson = File.OpenText(policyConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["policy"] = jObjectJson["policy"]; + } + //读取"inbounds" + using (StreamReader readerJson = File.OpenText(inboundsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["inbounds"] = jObjectJson["inbounds"]; + } + //读取"outbounds" + using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["outbounds"] = jObjectJson["outbounds"]; + } + //读取"transport" + using (StreamReader readerJson = File.OpenText(transportConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["transport"] = jObjectJson["transport"]; + } + //读取"stats" + using (StreamReader readerJson = File.OpenText(statsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["stats"] = jObjectJson["stats"]; + } + //读取"reverse" + using (StreamReader readerJson = File.OpenText(reverseConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + clientJson["reverse"] = jObjectJson["reverse"]; + } + + //根据不同的安装方案,选择相应的客户端模板 + if (String.Equals(ReceiveConfigurationParameters[0], "VlessVmessXtlsTcpWebSocketWeb") == false) + { + #region 单模式方案 + //根据选择的不同模式,选择相应的配置文件 + if (String.Equals(ReceiveConfigurationParameters[0], "TCP") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_http_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcp_TLS_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\tcpTLSselfSigned_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_xtls_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessTcpTlsWeb") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_tls_caddy_cilent_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_ws_tls_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\vless_http2_tls_server_config.json"; + } + + else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\webSocket_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocket_TLS_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLS_selfSigned_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLSWeb_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\http2_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\Http2Web_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\Http2selfSigned_client_config.json"; + } + //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\mkcp_client_config.json"; + } + // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("Quic") == true) + { + outboundsConfigJson = @"TemplateConfg\v2ray\client\06_outbounds\quic_client_config.json"; + } + + + //读取"相应模板的outbounds" + using (StreamReader readerJson = File.OpenText(outboundsConfigJson)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + + + //设置WebSocket模式下的path + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true + || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessWebSocketTlsWeb") == true) + { + jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; + } + + //设置http2模式下的path + if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true + || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + jObjectJson["outbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[6]; + } + + //设置http2+TLS+Web/VLESS+http2+TLS+Web模式下的host + if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true + || String.Equals(ReceiveConfigurationParameters[0], "VlessHttp2Web") == true) + { + jObjectJson["outbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; + } + + //设置VLESS+TCP+XTLS+Web模式下的serverName + //if (String.Equals(ReceiveConfigurationParameters[0], "VlessXtlsTcp") == true) + //{ + // jObjectJson["outbounds"][0]["streamSettings"]["xtlsSettings"]["serverName"] = ReceiveConfigurationParameters[4]; + //} + + //设置mkcp + if (ReceiveConfigurationParameters[0].Contains("mKCP") == true) + { + jObjectJson["outbounds"][0]["streamSettings"]["kcpSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[6]) == false) + { + jObjectJson["outbounds"][0]["streamSettings"]["kcpSettings"]["seed"] = ReceiveConfigurationParameters[6]; + } + } + + //设置QUIC + if (ReceiveConfigurationParameters[0].Contains("Quic") == true) + { + jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; + jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["security"] = ReceiveConfigurationParameters[3]; + if (String.Equals(ReceiveConfigurationParameters[3], "none") == true) + { + ReceiveConfigurationParameters[6] = ""; + } + jObjectJson["outbounds"][0]["streamSettings"]["quicSettings"]["key"] = ReceiveConfigurationParameters[6]; + } + + clientJson["outbounds"] = jObjectJson["outbounds"]; + + } + + using (StreamWriter sw = new StreamWriter(@"v2ray_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + + #endregion + + } + else + { + //复合方案所需要的配置文件 + //VLESS over TCP with XTLS模式 + string outboundsConfigJsonVlessXtls = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_xtls_client_config.json"; + using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessXtls)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + + clientJson["outbounds"] = jObjectJson["outbounds"]; + if (!Directory.Exists(@"v2ray_config\vless_tcp_xtls_client_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory(@"v2ray_config\vless_tcp_xtls_client_config");//创建该文件夹   + } + using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_tcp_xtls_client_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + } + + //VLESS over TCP with TLS模式 + string outboundsConfigJsonVlessTcpTls = @"TemplateConfg\v2ray\client\06_outbounds\vless_tcp_tls_caddy_cilent_config.json"; + using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessTcpTls)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + + clientJson["outbounds"] = jObjectJson["outbounds"]; + if (!Directory.Exists(@"v2ray_config\vless_tcp_tls_client_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory(@"v2ray_config\vless_tcp_tls_client_config");//创建该文件夹   + } + using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_tcp_tls_client_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + } + + //VLESS over WS with TLS 模式 + string outboundsConfigJsonVlessWsTls = @"TemplateConfg\v2ray\client\06_outbounds\vless_ws_tls_client_config.json"; + using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVlessWsTls)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; + + clientJson["outbounds"] = jObjectJson["outbounds"]; + if (!Directory.Exists(@"v2ray_config\vless_ws_tls_client_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory(@"v2ray_config\vless_ws_tls_client_config");//创建该文件夹   + } + using (StreamWriter sw = new StreamWriter(@"v2ray_config\vless_ws_tls_client_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + } + + //VMess over TCP with TLS模式 + string outboundsConfigJsonVmessTcpTls = @"TemplateConfg\v2ray\client\06_outbounds\vmess_tcp_tls_client_config.json"; + using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVmessTcpTls)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + jObjectJson["outbounds"][0]["streamSettings"]["tcpSettings"]["header"]["request"]["path"][0] = ReceiveConfigurationParameters[9]; + + clientJson["outbounds"] = jObjectJson["outbounds"]; + if (!Directory.Exists(@"v2ray_config\vmess_tcp_tls_client_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory(@"v2ray_config\vmess_tcp_tls_client_config");//创建该文件夹   + } + using (StreamWriter sw = new StreamWriter(@"v2ray_config\vmess_tcp_tls_client_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + } + + //VMess over WS with TLS模式 + string outboundsConfigJsonVmessWsTls = @"TemplateConfg\v2ray\client\06_outbounds\WebSocketTLSWeb_client_config.json"; + using (StreamReader readerJson = File.OpenText(outboundsConfigJsonVmessWsTls)) + { + JObject jObjectJson = (JObject)JToken.ReadFrom(new JsonTextReader(readerJson)); + + //设置客户端的地址/端口/id + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); + jObjectJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; + jObjectJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[6]; + + clientJson["outbounds"] = jObjectJson["outbounds"]; + if (!Directory.Exists(@"v2ray_config\vmess_ws_tls_client_config"))//如果不存在就创建file文件夹      + { + Directory.CreateDirectory(@"v2ray_config\vmess_ws_tls_client_config");//创建该文件夹   + } + using (StreamWriter sw = new StreamWriter(@"v2ray_config\vmess_ws_tls_client_config\config.json")) + { + sw.Write(clientJson.ToString()); + } + } + + } + } + SetUpProgressBarProcessing(98); + return true; + } + + + #endregion //检测升级远程主机端的V2Ray版本 private void ButtonUpdateV2ray_Click(object sender, RoutedEventArgs e) @@ -3621,8 +2525,6 @@ namespace ProxySU return; } - - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == true) { //******"请先选择配置模板!"****** @@ -3636,6 +2538,7 @@ namespace ProxySU return; } installationDegree = 0; + TextBoxMonitorCommandResults.Text = ""; Thread thread = new Thread(() => StartSetUpTrojanGo(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); thread.SetApartmentState(ApartmentState.STA); thread.Start(); @@ -3644,12 +2547,15 @@ namespace ProxySU //登录远程主机布署Trojan-Go程序 private void StartSetUpTrojanGo(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) { + functionResult = true; + getApt = false; + getDnf = false; + getYum = false; + //******"正在登录远程主机......"****** SetUpProgressBarProcessing(1); string currentStatus = Application.Current.FindResource("DisplayInstallInfo_Login").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); try { @@ -3689,737 +2595,66 @@ namespace ProxySU //******"主机登录成功"****** SetUpProgressBarProcessing(3); currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginSuccessful").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果在监视窗口 - - //Thread.Sleep(1000); - } - - //******"检测是否运行在root权限下..."****** - SetUpProgressBarProcessing(5); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootPermission").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"id -u"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string testRootAuthority = currentShellCommandResult; - if (testRootAuthority.Equals("0\n") == false) - { - //******"请使用具有root权限的账户登录主机!!"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorRootPermission").ToString()); - client.Disconnect(); - return; - } - else - { - //******"检测结果:OK!"****** - SetUpProgressBarProcessing(8); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //******"检测系统是否已经安装Trojan-go......"****** - SetUpProgressBarProcessing(10); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestExistSoft").ToString() + "Trojan-go......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"find / -name trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string resultCmdTestTrojanInstalled = currentShellCommandResult; - - if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan-go") == true) - { - - MessageBoxResult messageBoxResult = MessageBox.Show( - //******"远程主机已安装"****** - Application.Current.FindResource("MessageBoxShow_ExistedSoft").ToString() + - "Trojan-go" + - //******",是否强制重新安装?"****** - Application.Current.FindResource("MessageBoxShow_ForceInstallSoft").ToString(), "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult == MessageBoxResult.No) - { - //******"安装取消,退出"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstallationCanceledExit").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - else - { - //******"已选择强制安装Trojan-go!"****** - SetUpProgressBarProcessing(12); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ForceInstallSoft").ToString() + "Trojan-go!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - } - } - else - { - //******"检测结果:未安装Trojan-go!"****** - SetUpProgressBarProcessing(12); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_NoInstalledSoft").ToString() + "Trojan-go!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus);//显示命令执行的结果 - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); } - //******"检测系统是否符合安装要求......"****** - SetUpProgressBarProcessing(14); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_CheckSystemRequirements").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //检测root权限 5--7 + functionResult = RootAuthorityDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //Thread.Sleep(1000); + //检测是否已安装代理 8--10 + functionResult = SoftInstalledIsNoYes(client, "trojan-go", @"/usr/local/bin/trojan-go"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + //检测关闭Selinux及系统组件是否齐全(apt/yum/dnf/systemctl)11--30 + //安装依赖软件,检测端口,防火墙开启端口 + functionResult = ShutDownSelinuxAndSysComponentsDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //检测系统是否支持dnf\yum 或 apt或zypper,且支持Systemd - //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真, - //bool getApt = String.IsNullOrEmpty(client.RunCommand("command -v apt").Result); - //bool getDnf = String.IsNullOrEmpty(client.RunCommand("command -v dnf").Result); - //bool getYum = String.IsNullOrEmpty(client.RunCommand("command -v yum").Result); - //bool getZypper = String.IsNullOrEmpty(client.RunCommand("command -v zypper").Result); - //bool getSystemd = String.IsNullOrEmpty(client.RunCommand("command -v systemctl").Result); - //bool getGetenforce = String.IsNullOrEmpty(client.RunCommand("command -v getenforce").Result); + //检测域名是否解析到当前IP上 34---36 + functionResult = DomainResolutionCurrentIPDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"command -v apt"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getApt = String.IsNullOrEmpty(currentShellCommandResult); + //下载脚本安装Trojan-go 37--40 + functionResult = TrojanGoInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"command -v dnf"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getDnf = String.IsNullOrEmpty(currentShellCommandResult); + //程序是否安装成功检测并设置开机启动 41--43 + functionResult = SoftInstalledSuccessOrFail(client, "trojan-go", @"/usr/local/bin/trojan-go"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"command -v yum"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getYum = String.IsNullOrEmpty(currentShellCommandResult); + //生成Trojan-go服务端配置 44--46 + functionResult = GenerateServerConfigurationTrojanGo(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - SetUpProgressBarProcessing(16); - - sshShellCommand = @"command -v zypper"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getZypper = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v systemctl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getSystemd = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getGetenforce = String.IsNullOrEmpty(currentShellCommandResult); - - //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 - //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 - if ((getApt && getDnf && getYum && getZypper) || getSystemd) - { - //******"系统缺乏必要的安装组件如:apt||dnf||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_MissingSystemComponents").ToString()); - - //******"系统环境不满足要求,安装失败!!"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - else - { - //******"检测结果:OK!"****** - SetUpProgressBarProcessing(18); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SystemRequirementsOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //设置安装软件所用的命令格式 - //为假则表示系统有相应的组件。 - - if (getApt == false) - { - sshCmdUpdate = @"apt -qq update"; - sshCmdInstall = @"apt -y -qq install "; - } - else if (getDnf == false) - { - sshCmdUpdate = @"dnf -q makecache"; - sshCmdInstall = @"dnf -y -q install "; - } - else if (getYum == false) - { - sshCmdUpdate = @"yum -q makecache"; - sshCmdInstall = @"yum -y -q install "; - } - else if (getZypper == false) - { - sshCmdUpdate = @"zypper ref"; - sshCmdInstall = @"zypper -y install "; - } - - //判断是否启用了SELinux,如果启用了,并且工作在Enforcing模式下,则改为Permissive模式 - if (getGetenforce == false) - { - sshShellCommand = @"getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string testSELinux = currentShellCommandResult; - - if (testSELinux.Contains("Enforcing") == true) - { - //******"检测到系统启用SELinux,且工作在严格模式下,需改为宽松模式!修改中......"****** - SetUpProgressBarProcessing(20); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableSELinux").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"setenforce 0"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - sshShellCommand = @"sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //******"修改完毕!"****** - SetUpProgressBarProcessing(22); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SELinuxModifyOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - } - - //****** "正在检测域名是否解析到当前VPS的IP上......" ****** - SetUpProgressBarProcessing(28); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestDomainResolve").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //在相应系统内安装curl(如果没有安装curl) - if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}curl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - sshShellCommand = @"curl -4 ip.sb"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string nativeIp = currentShellCommandResult; - - sshShellCommand = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string resultTestDomainCmd = currentShellCommandResult; - - if (String.Equals(nativeIp, resultTestDomainCmd) == true) - { - //****** "解析正确!OK!" ****** - SetUpProgressBarProcessing(32); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DomainResolveOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "域名未能正确解析到当前VPS的IP上!安装失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorDomainResolve").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //****** "域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!" ****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorDomainResolve").ToString()); - client.Disconnect(); - return; - } - - //检测是否安装lsof - if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}lsof"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - } - //****** "检测端口占用情况......" ****** - SetUpProgressBarProcessing(34); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestPortUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"lsof -n -P -i :80 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort80 = currentShellCommandResult; - - sshShellCommand = @"lsof -n -P -i :443 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort443 = currentShellCommandResult; - - if (String.IsNullOrEmpty(testPort80) == false || String.IsNullOrEmpty(testPort443) == false) - { - //****** "80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?" ****** - MessageBoxResult dialogResult = MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorPortUsed").ToString(), "Stop application", MessageBoxButton.YesNo); - if (dialogResult == MessageBoxResult.No) - { - //****** "端口被占用,安装失败......" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorPortUsedFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - - //****** "正在释放80/443端口......" ****** - SetUpProgressBarProcessing(37); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - if (String.IsNullOrEmpty(testPort443) == false) - { - string[] cmdResultArry443 = testPort443.Split(' '); - - sshShellCommand = $"systemctl stop {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry443[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - - if (String.IsNullOrEmpty(testPort80) == false) - { - string[] cmdResultArry80 = testPort80.Split(' '); - - sshShellCommand = $"systemctl stop {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry80[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "80/443端口释放完毕!" ****** - SetUpProgressBarProcessing(39); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "检测结果:未被占用!" ****** - SetUpProgressBarProcessing(41); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_PortNotUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //****** "系统环境检测完毕,符合安装要求,开始布署......" ****** - SetUpProgressBarProcessing(43); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //****** "开启防火墙相应端口......" ****** - SetUpProgressBarProcessing(44); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_OpenFireWallPort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (String.IsNullOrEmpty(client.RunCommand("command -v firewall-cmd").Result) == false) - { - - sshShellCommand = @"firewall-cmd --zone=public --add-port=80/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"firewall-cmd --zone=public --add-port=443/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | firewall-cmd --reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - if (String.IsNullOrEmpty(client.RunCommand("command -v ufw").Result) == false) - { - - sshShellCommand = @"ufw allow 80"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"ufw allow 443"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | ufw reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //下载安装脚本安装 - //****** "正在安装Trojan-go......" ****** - SetUpProgressBarProcessing(46); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "Trojan-go......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"curl -o /tmp/trojan-go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | bash /tmp/trojan-go.sh -f"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"rm -f /tmp/trojan-go.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - sshShellCommand = @"find / -name trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string installResult = currentShellCommandResult; - - if (!installResult.Contains("/usr/local/bin/trojan-go")) - { - //****** "安装失败,官方脚本运行出错!" ****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString()); - //****** "安装失败,官方脚本运行出错!" ****** - currentStatus = Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - client.Disconnect(); - return; - } - else - { - //****** "Trojan-go安装成功!" ****** - SetUpProgressBarProcessing(50); - currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_SoftInstallSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"systemctl enable trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - sshShellCommand = @"mv /etc/trojan-go/config.json /etc/trojan-go/config.json.1"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //****** "安装完毕,上传配置文件......" ****** - SetUpProgressBarProcessing(53); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadSoftConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - string serverConfig = @"TemplateConfg\trojan-go\trojan-go_all_config.json"; //服务端配置文件 - string upLoadPath = @"/usr/local/etc/trojan-go/config.json"; //服务端文件位置 - - //生成服务端配置 - using (StreamReader reader = File.OpenText(serverConfig)) - { - //设置Caddy随机监听的端口,用于Trojan-go,Trojan,V2Ray vless TLS - //Random random = new Random(); - randomCaddyListenPort = GetRandomPort(); - - JObject serverJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); - serverJson["run_type"] = "server"; - serverJson["local_addr"] = "0.0.0.0"; - serverJson["local_port"] = 443; - serverJson["remote_addr"] = "127.0.0.1"; - serverJson["remote_port"] = randomCaddyListenPort; - //设置密码 - serverJson["password"][0] = ReceiveConfigurationParameters[2]; - //设置证书 - serverJson["ssl"]["cert"] = "/usr/local/etc/trojan-go/trojan-go.crt"; - serverJson["ssl"]["key"] = "/usr/local/etc/trojan-go/trojan-go.key"; - //serverJson["ssl"]["sni"] = ReceiveConfigurationParameters[4]; - - if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoWebSocketTLS2Web")) - { - serverJson["websocket"]["enabled"] = true; - serverJson["websocket"]["path"] = ReceiveConfigurationParameters[6]; - } - - using (StreamWriter sw = new StreamWriter(@"config.json")) - { - sw.Write(serverJson.ToString()); - } - } - upLoadPath = "/usr/local/etc/trojan-go/config.json"; + //上传配置文件 + string upLoadPath = "/usr/local/etc/trojan-go/config.json"; UploadConfig(connectionInfo, @"config.json", upLoadPath); - File.Delete(@"config.json"); - //****** "正在安装acme.sh......" ****** - SetUpProgressBarProcessing(55); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallAcmeSh").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //acme.sh安装与申请证书 51--57 + functionResult = AcmeShInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //Thread.Sleep(1000); - - //安装所依赖的软件 - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}socat"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //解决搬瓦工CentOS缺少问题 - sshShellCommand = $"{sshCmdInstall}automake autoconf libtool"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("Install success") == true) - { - //****** "acme.sh安装成功!" ****** - SetUpProgressBarProcessing(58); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_AcmeShInstallSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "acme.sh安装失败!原因未知,请向开发者提问!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorAcmeShInstallFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - return; - } - - sshShellCommand = @"cd ~/.acme.sh/"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"alias acme.sh=~/.acme.sh/acme.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - //****** "申请域名证书......" ****** - SetUpProgressBarProcessing(60); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartApplyCert").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = $"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("Cert success") == true) - { - //****** "证书申请成功!" ****** - SetUpProgressBarProcessing(63); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "证书申请失败!原因未知,请向开发者提问!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - return; - } + //****** "安装证书到Trojan-go......" ****** - SetUpProgressBarProcessing(65); + SetUpProgressBarProcessing(58); currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoft").ToString() + "Trojan-go......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); - //Thread.Sleep(1000); - sshShellCommand = $"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/trojan-go/trojan-go.crt --keypath /usr/local/etc/trojan-go/trojan-go.key --capath /usr/local/etc/trojan-go/trojan-go.crt --reloadcmd \"systemctl restart trojan-go\""; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + sshShellCommand = $"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/trojan-go/trojan-go.crt --keypath /usr/local/etc/trojan-go/trojan-go.key --capath /usr/local/etc/trojan-go/trojan-go.crt --reloadcmd \"systemctl restart trojan-go\""; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); sshShellCommand = @"if [ ! -f ""/usr/local/etc/trojan-go/trojan-go.key"" ]; then echo ""0""; else echo ""1""; fi | head -n 1"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); if (currentShellCommandResult.Contains("1") == true) { //****** "证书成功安装到Trojan-go!" ****** - SetUpProgressBarProcessing(68); + SetUpProgressBarProcessing(60); currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftOK").ToString() + "Trojan-go!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } else { @@ -4427,148 +2662,27 @@ namespace ProxySU currentStatus = Application.Current.FindResource("DisplayInstallInfo_IntallCertToSoftFail").ToString() + "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_InstallCertFailAsk").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); + client.Disconnect(); return; } //设置证书权限 sshShellCommand = @"chmod 644 /usr/local/etc/trojan-go/trojan-go.key"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); - //****** "安装Caddy......" ****** - SetUpProgressBarProcessing(70); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallCaddy").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //安装Caddy - //为假则表示系统有相应的组件。 - if (getApt == false) - { - sshShellCommand = @"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt install -y apt-transport-https"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt -qq update"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"apt -y -qq install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else if (getDnf == false) - { - sshShellCommand = @"dnf install 'dnf-command(copr)' -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"dnf copr enable @caddy/caddy -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //sshShellCommand = @"dnf -q makecache"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"dnf -y -q install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else if (getYum == false) - { - sshShellCommand = @"yum install yum-plugin-copr -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yum copr enable @caddy/caddy -y"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //sshShellCommand = @"yum -q makecache"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yum -y -q install caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - sshShellCommand = @"find / -name caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - installResult = currentShellCommandResult; - - if (!installResult.Contains("/usr/bin/caddy")) - { - //****** "安装Caddy失败!" ****** - MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString()); - //****** "安装Caddy失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - client.Disconnect(); - return; - } - - //****** "Caddy安装成功!" ****** - SetUpProgressBarProcessing(75); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstalledCaddyOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"systemctl enable caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //Caddy安装 61--66 + functionResult = CaddyInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + //****** "上传Caddy配置文件......" ****** - SetUpProgressBarProcessing(80); + SetUpProgressBarProcessing(67); currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); sshShellCommand = @"mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); string caddyConfig = @"TemplateConfg\trojan-go\trojan-go.caddyfile"; @@ -4581,283 +2695,44 @@ namespace ProxySU string randomCaddyListenPortStr = randomCaddyListenPort.ToString(); sshShellCommand = $"sed -i 's/8800/{randomCaddyListenPortStr}/' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); //设置域名 sshShellCommand = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}/g' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); - //client.RunCommand(sshCmd); //设置伪装网站 if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) { sshShellCommand = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); } //****** "Caddy配置文件上传成功,OK!" ****** - SetUpProgressBarProcessing(85); + SetUpProgressBarProcessing(70); currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfigOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); - //Thread.Sleep(1000); + //程序启动检测Caddy + functionResult = SoftStartDetect(client, "caddy", @"/usr/bin/caddy"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //****** "正在启动Caddy......" ****** - SetUpProgressBarProcessing(87); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyService").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //程序启动检测Trojan-go + functionResult = SoftStartDetect(client, "trojan-go", @"/usr/local/bin/trojan-go"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //Thread.Sleep(1000); - //启动Caddy服务 - sshShellCommand = @"systemctl restart caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); + //检测BBR,满足条件并启动 90--95 + functionResult = DetectBBRandEnable(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"ps aux | grep caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - { - //****** "Caddy启动成功!" ****** - SetUpProgressBarProcessing(88); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Caddy启动失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - - //****** "正在启动Caddy(第二次尝试)!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecond").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - sshShellCommand = @"systemctl restart caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep caddy"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - { - //****** "Caddy启动成功!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Caddy启动失败(第二次)!退出安装!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecondFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - //****** "Caddy启动失败,原因未知!请向开发者问询!" ****** - MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_CaddyServiceFailedExit").ToString()); - return; - } - } - - //****** "正在启动Trojan-go......" ****** - SetUpProgressBarProcessing(90); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoft").ToString() + "Trojan-go......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //启动Trojan-go服务 - - sshShellCommand = @"systemctl restart trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - if (currentShellCommandResult.Contains("/usr/local/bin/trojan-go") == true) - { - //****** "Trojan-go启动成功!" ****** - SetUpProgressBarProcessing(93); - currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Trojan-go启动失败!" ****** - currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - - //****** "正在第二次尝试启动Trojan-go!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoftSecond").ToString() + "Trojan-go!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - sshShellCommand = @"systemctl restart trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep trojan-go"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("usr/local/bin/trojan-go") == true) - { - //****** "Trojan-go启动成功!" ****** - currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "Trojan-go启动失败(第二次)!退出安装!" ****** - currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_StartSoftSecondFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - //****** "Trojan-go启动失败,原因未知!请向开发者问询!" ****** - MessageBox.Show("Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFailedExit").ToString()); - return; - } - } - - - //测试BBR条件,若满足提示是否启用 - //****** "BBR测试......" ****** - SetUpProgressBarProcessing(95); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"uname -r"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string[] linuxKernelVerStr = currentShellCommandResult.Split('-'); - - bool detectResult = DetectKernelVersionBBR(linuxKernelVerStr[0]); - - sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string resultCmdTestBBR = currentShellCommandResult; - //如果内核满足大于等于4.9,且还未启用BBR,则启用BBR - if (detectResult == true && resultCmdTestBBR.Contains("bbr") == false) - { - //****** "正在启用BBR......" ****** - SetUpProgressBarProcessing(97); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"bash -c 'echo ""net.core.default_qdisc=fq"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"bash -c 'echo ""net.ipv4.tcp_congestion_control=bbr"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"sysctl -p"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else if (resultCmdTestBBR.Contains("bbr") == true) - { - //****** "BBR已经启用了!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRisEnabled").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - //****** "系统不满足启用BBR的条件,启用失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } + client.Disconnect();//断开服务器ssh连接 //****** "生成客户端配置......" ****** - SetUpProgressBarProcessing(99); + SetUpProgressBarProcessing(96); currentStatus = Application.Current.FindResource("DisplayInstallInfo_GenerateClientConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); if (!Directory.Exists("trojan-go_config"))//如果不存在就创建file文件夹      { @@ -4892,11 +2767,7 @@ namespace ProxySU //****** "Trojan-go安装成功,祝你玩的愉快!!" ****** SetUpProgressBarProcessing(100); currentStatus = "Trojan-go" + Application.Current.FindResource("DisplayInstallInfo_ProxyInstalledOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); //显示服务端连接参数 @@ -4912,17 +2783,97 @@ namespace ProxySU { ProcessException(ex1.Message); - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } #endregion } + //下载脚本安装Trojan-go 37--40 + //functionResult = TrojanGoInstall(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool TrojanGoInstall(SshClient client) + { + //****** "系统环境检测完毕,符合安装要求,开始布署......" ****** + SetUpProgressBarProcessing(37); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); + MainWindowsShowInfo(currentStatus); + + //****** "正在安装Trojan-go......" ****** + SetUpProgressBarProcessing(38); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "Trojan-go......"; + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"curl -o /tmp/trojan-go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | bash /tmp/trojan-go.sh -f"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"rm -f /tmp/trojan-go.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + SetUpProgressBarProcessing(40); + return true; + } + + //生成Trojan-go服务端配置 44--46 + //functionResult = GenerateServerConfigurationTrojanGo(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool GenerateServerConfigurationTrojanGo(SshClient client) + { + //备份原配置文件 + sshShellCommand = @"mv /etc/trojan-go/config.json /etc/trojan-go/config.json.1"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //****** "安装完毕,上传配置文件......" ****** + SetUpProgressBarProcessing(44); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadSoftConfig").ToString(); + MainWindowsShowInfo(currentStatus); + + string serverConfig = @"TemplateConfg\trojan-go\trojan-go_all_config.json"; //服务端配置文件 + string upLoadPath = @"/usr/local/etc/trojan-go/config.json"; //服务端文件位置 + + //生成服务端配置 + using (StreamReader reader = File.OpenText(serverConfig)) + { + //设置Caddy随机监听的端口,用于Trojan-go,Trojan,V2Ray vless TLS + //Random random = new Random(); + randomCaddyListenPort = GetRandomPort(); + + JObject serverJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); + serverJson["run_type"] = "server"; + serverJson["local_addr"] = "0.0.0.0"; + serverJson["local_port"] = 443; + serverJson["remote_addr"] = "127.0.0.1"; + serverJson["remote_port"] = randomCaddyListenPort; + //设置密码 + serverJson["password"][0] = ReceiveConfigurationParameters[2]; + //设置证书 + serverJson["ssl"]["cert"] = "/usr/local/etc/trojan-go/trojan-go.crt"; + serverJson["ssl"]["key"] = "/usr/local/etc/trojan-go/trojan-go.key"; + //serverJson["ssl"]["sni"] = ReceiveConfigurationParameters[4]; + + if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoWebSocketTLS2Web")) + { + serverJson["websocket"]["enabled"] = true; + serverJson["websocket"]["path"] = ReceiveConfigurationParameters[6]; + } + + using (StreamWriter sw = new StreamWriter(@"config.json")) + { + sw.Write(serverJson.ToString()); + } + } + + + SetUpProgressBarProcessing(46); + return true; + } + + //检测升级Trojan-Go版本传递参数 private void ButtonUpdateTrojanGo_Click(object sender, RoutedEventArgs e) { @@ -6542,12 +4493,9 @@ namespace ProxySU { ProcessException(ex1.Message); - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } #endregion @@ -7666,12 +5614,6 @@ namespace ProxySU currentShellCommandResult = currentStatus; TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - //currentStatus = "设置Caddy自启配置文件......"; - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 sshShellCommand = @"sed -i 's/Caddyfile/config.json/' /lib/systemd/system/caddy.service"; TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 @@ -8005,12 +5947,10 @@ namespace ProxySU #region 例外处理 { ProcessException(ex1.Message); - //****** "主机登录失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //****** "安装失败!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); + MainWindowsShowInfo(currentStatus); } #endregion @@ -8257,28 +6197,7 @@ namespace ProxySU currentShellCommandResult = currentStatus; TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - //sshShellCommand = @"uname -m"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //string resultCmd = currentShellCommandResult; - //if (resultCmd.Contains("x86_64") == false) - //{ - // //******"请在x86_64系统中安装Trojan" ****** - // MessageBox.Show(Application.Current.FindResource("MessageBoxShow_PleaseInstallSoftAtX64").ToString() + "NaiveProxy......"); - // //****** "系统环境不满足要求,安装失败!!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // Thread.Sleep(1000); - //} - - + //检测系统是否支持yum 或 apt或zypper,且支持Systemd //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真 @@ -9214,12 +7133,9 @@ namespace ProxySU { ProcessException(ex1.Message); - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } #endregion @@ -11092,53 +9008,9 @@ namespace ProxySU { ProcessException(ex1.Message); - #region 旧代码 - //string exceptionMessage = ex1.Message; - //if (exceptionMessage.Contains("连接尝试失败") == true) - //{ - // //****** "请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作!" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginHostOrPort").ToString()); - //} - - //else if (exceptionMessage.Contains("denied (password)") == true) - //{ - // //****** "密码错误或用户名错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginUserOrPassword").ToString()); - //} - //else if (exceptionMessage.Contains("Invalid private key file") == true) - //{ - // //****** "所选密钥文件错误或者格式不对!" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginKey").ToString()); - //} - //else if (exceptionMessage.Contains("denied (publickey)") == true) - //{ - // //****** "使用密钥登录,密钥文件错误或用户名错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginKeyOrUser").ToString()); - //} - //else if (exceptionMessage.Contains("目标计算机积极拒绝") == true) - //{ - // //****** "主机地址错误,如果使用了代理,也可能是连接代理的端口错误" ****** - // MessageBox.Show($"{exceptionMessage}\n" + - // Application.Current.FindResource("MessageBoxShow_ErrorLoginHostOrProxyPort").ToString()); - //} - //else - //{ - // //****** "发生错误" ****** - // MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorLoginOccurred").ToString()); - // MessageBox.Show(exceptionMessage); - //} - #endregion - - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } #endregion } @@ -11188,6 +9060,7 @@ namespace ProxySU ReceiveConfigurationParameters[7] = TextBoxMtgSites.Text; } installationDegree = 0; + TextBoxMonitorCommandResults.Text = ""; Thread thread = new Thread(() => StartSetUpMtg(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); thread.SetApartmentState(ApartmentState.STA); thread.Start(); @@ -11196,12 +9069,15 @@ namespace ProxySU //Mtg安装进程 private void StartSetUpMtg(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) { + functionResult = true; + getApt = false; + getDnf = false; + getYum = false; + //******"正在登录远程主机......"****** SetUpProgressBarProcessing(1); string currentStatus = Application.Current.FindResource("DisplayInstallInfo_Login").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + MainWindowsShowInfo(currentStatus); try { @@ -11241,116 +9117,25 @@ namespace ProxySU //******"主机登录成功"****** SetUpProgressBarProcessing(3); currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginSuccessful").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果在监视窗口 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); } - //******"检测是否运行在root权限下..."****** - SetUpProgressBarProcessing(5); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootPermission").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //检测root权限 5--7 + functionResult = RootAuthorityDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - sshShellCommand = @"id -u"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //检测是否已安装代理 8--10 + functionResult = SoftInstalledIsNoYes(client, "mtg", @"/usr/local/bin/mtg"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - string testRootAuthority = currentShellCommandResult; - if (testRootAuthority.Equals("0\n") == false) - { - //******"请使用具有root权限的账户登录主机!!"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorRootPermission").ToString()); - client.Disconnect(); - return; - } - else - { - //******"检测结果:OK!"****** - SetUpProgressBarProcessing(8); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //******"检测系统是否已经安装MTProto......"****** - SetUpProgressBarProcessing(10); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestExistSoft").ToString() + "MTProto......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"if [ -f /usr/local/bin/mtg ];then echo '1';else echo '0'; fi"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string resultCmdTestTrojanInstalled = currentShellCommandResult; - - if (resultCmdTestTrojanInstalled.Contains("1") == true) - { - MessageBoxResult messageBoxResult = MessageBox.Show( - //******"远程主机已安装"****** - Application.Current.FindResource("MessageBoxShow_ExistedSoft").ToString() + - "MTProto" + - //******",是否强制重新安装?"****** - Application.Current.FindResource("MessageBoxShow_ForceInstallSoft").ToString(), "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult == MessageBoxResult.No) - { - //******"安装取消,退出"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstallationCanceledExit").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - else - { - //******"已选择强制安装MTProto!"****** - SetUpProgressBarProcessing(11); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ForceInstallSoft").ToString() + "MTProto!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - } - } - else - { - //******"检测结果:未安装MTProto!"****** - SetUpProgressBarProcessing(12); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_NoInstalledSoft").ToString() + "MTProto!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus);//显示命令执行的结果 - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //******"检测系统是否符合安装要求......"****** - SetUpProgressBarProcessing(14); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_CheckSystemRequirements").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + //检测关闭Selinux及系统组件是否齐全(apt/yum/dnf/systemctl)11--30 + //安装依赖软件,检测端口,防火墙开启端口 + functionResult = ShutDownSelinuxAndSysComponentsDetect(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + //检测是否为64位系统 sshShellCommand = @"uname -m"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); string resultCmd = currentShellCommandResult; if (resultCmd.Contains("x86_64") == false) { @@ -11358,994 +9143,37 @@ namespace ProxySU MessageBox.Show(Application.Current.FindResource("MessageBoxShow_PleaseInstallSoftAtX64").ToString() + "MTProto......"); //****** "系统环境不满足要求,安装失败!!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // Thread.Sleep(1000); - } - - - //检测系统是否支持yum 或 apt或zypper,且支持Systemd - //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真 - - //bool getApt = String.IsNullOrEmpty(client.RunCommand("command -v apt").Result); - //bool getDnf = String.IsNullOrEmpty(client.RunCommand("command -v dnf").Result); - //bool getYum = String.IsNullOrEmpty(client.RunCommand("command -v yum").Result); - //bool getZypper = String.IsNullOrEmpty(client.RunCommand("command -v zypper").Result); - //bool getSystemd = String.IsNullOrEmpty(client.RunCommand("command -v systemctl").Result); - //bool getGetenforce = String.IsNullOrEmpty(client.RunCommand("command -v getenforce").Result); - - sshShellCommand = @"command -v apt"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getApt = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v dnf"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getDnf = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v yum"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getYum = String.IsNullOrEmpty(currentShellCommandResult); - - SetUpProgressBarProcessing(16); - - sshShellCommand = @"command -v zypper"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getZypper = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v systemctl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getSystemd = String.IsNullOrEmpty(currentShellCommandResult); - - sshShellCommand = @"command -v getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - bool getGetenforce = String.IsNullOrEmpty(currentShellCommandResult); - - - //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 - //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 - if ((getApt && getDnf && getYum && getZypper) || getSystemd) - { - //******"系统缺乏必要的安装组件如:apt||dnf||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_MissingSystemComponents").ToString()); - - //******"系统环境不满足要求,安装失败!!"****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); + MainWindowsShowInfo(currentStatus); return; } - else - { - //******"检测结果:OK!"****** - SetUpProgressBarProcessing(18); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SystemRequirementsOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - } - //设置安装软件所用的命令格式 - //为假则表示系统有相应的组件。 + //下载安装脚本安装MTProto 37--40 + functionResult = MTProtoInstall(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - if (getApt == false) - { - sshCmdUpdate = @"apt -qq update"; - sshCmdInstall = @"apt -y -qq install "; - } - else if (getDnf == false) - { - sshCmdUpdate = @"dnf -q makecache"; - sshCmdInstall = @"dnf -y -q install "; - } - else if (getYum == false) - { - sshCmdUpdate = @"yum -q makecache"; - sshCmdInstall = @"yum -y -q install "; - } - else if (getZypper == false) - { - sshCmdUpdate = @"zypper ref"; - sshCmdInstall = @"zypper -y install "; - } - - //判断是否启用了SELinux,如果启用了,并且工作在Enforcing模式下,则改为Permissive模式 - if (getGetenforce == false) - { - sshShellCommand = @"getenforce"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string testSELinux = currentShellCommandResult; - - if (testSELinux.Contains("Enforcing") == true) - { - //******"检测到系统启用SELinux,且工作在严格模式下,需改为宽松模式!修改中......"****** - SetUpProgressBarProcessing(20); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableSELinux").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"setenforce 0"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - sshShellCommand = @"sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //******"修改完毕!"****** - SetUpProgressBarProcessing(22); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_SELinuxModifyOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - } - - //****** "正在检测域名是否解析到当前VPS的IP上......" ****** - //SetUpProgressBarProcessing(28); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestDomainResolve").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - //在相应系统内安装curl(如果没有安装curl) - if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}curl"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //安装wget - if (string.IsNullOrEmpty(client.RunCommand("command -v wget").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}wget"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - SetUpProgressBarProcessing(36); - //检测域名是否解析正确 - //sshShellCommand = @"curl -4 ip.sb"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //string nativeIp = currentShellCommandResult; - - //sshShellCommand = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //string resultTestDomainCmd = currentShellCommandResult; - //if (String.Equals(nativeIp, resultTestDomainCmd) == true) - //{ - // //****** "解析正确!OK!" ****** - // SetUpProgressBarProcessing(40); - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_DomainResolveOK").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //Thread.Sleep(1000); - //} - //else - //{ - // //****** "域名未能正确解析到当前VPS的IP上!安装失败!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorDomainResolve").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //Thread.Sleep(1000); - // //****** "域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!" ****** - // MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorDomainResolve").ToString()); - // client.Disconnect(); - // return; - //} - - //检测是否安装lsof - if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) - { - sshShellCommand = $"{sshCmdUpdate}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"{sshCmdInstall}lsof"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "检测端口占用情况......" ****** - SetUpProgressBarProcessing(45); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestPortUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"lsof -n -P -i :80 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort80 = currentShellCommandResult; - - sshShellCommand = @"lsof -n -P -i :443 | grep LISTEN"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string testPort443 = currentShellCommandResult; - - - if (String.IsNullOrEmpty(testPort80) == false || String.IsNullOrEmpty(testPort443) == false) - { - //****** "80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?" ****** - MessageBoxResult dialogResult = MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorPortUsed").ToString(), "Stop application", MessageBoxButton.YesNo); - if (dialogResult == MessageBoxResult.No) - { - //****** "端口被占用,安装失败......" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorPortUsedFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - client.Disconnect(); - return; - } - - //****** "正在释放80/443端口......" ****** - SetUpProgressBarProcessing(48); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - if (String.IsNullOrEmpty(testPort443) == false) - { - string[] cmdResultArry443 = testPort443.Split(' '); - - sshShellCommand = $"systemctl stop {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry443[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry443[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - if (String.IsNullOrEmpty(testPort80) == false) - { - string[] cmdResultArry80 = testPort80.Split(' '); - - sshShellCommand = $"systemctl stop {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"systemctl disable {cmdResultArry80[0]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"kill -9 {cmdResultArry80[3]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //****** "80/443端口释放完毕!" ****** - SetUpProgressBarProcessing(51); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "检测结果:未被占用!" ****** - SetUpProgressBarProcessing(52); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_PortNotUsed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - - //****** "系统环境检测完毕,符合安装要求,开始布署......" ****** - SetUpProgressBarProcessing(53); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //****** "开启防火墙相应端口......" ****** - SetUpProgressBarProcessing(54); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_OpenFireWallPort").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string openFireWallPort = ReceiveConfigurationParameters[1]; - if (String.IsNullOrEmpty(client.RunCommand("command -v firewall-cmd").Result) == false) - { - if (String.Equals(openFireWallPort, "443")) - { - sshShellCommand = @"firewall-cmd --zone=public --add-port=80/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"firewall-cmd --zone=public --add-port=80/udp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"firewall-cmd --zone=public --add-port=443/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"firewall-cmd --zone=public --add-port=443/udp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | firewall-cmd --reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - } - else - { - sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/tcp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/udp --permanent"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | firewall-cmd --reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - } - else if (String.IsNullOrEmpty(client.RunCommand("command -v ufw").Result) == false) - { - if (String.Equals(openFireWallPort, "443")) - { - sshShellCommand = @"ufw allow 80/tcp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"ufw allow 80/udp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"ufw allow 443/tcp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"ufw allow 443/udp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | ufw reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - sshShellCommand = $"ufw allow {openFireWallPort}/tcp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"ufw allow {openFireWallPort}/udp"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"yes | ufw reload"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - } - //处理极其少见的xz-utils未安装的情况 - //SetUpProgressBarProcessing(56); - //sshShellCommand = $"{sshCmdUpdate}"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //sshShellCommand = $"{sshCmdInstall}xz-utils"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //下载安装脚本安装 - //****** "正在安装MTProto......" ****** - SetUpProgressBarProcessing(58); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "MTProto......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"curl -o /tmp/mtg_install.sh https://raw.githubusercontent.com/proxysu/shellscript/master/MTProto/mtg_install.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = $"yes | bash /tmp/mtg_install.sh {ReceiveConfigurationParameters[1]} {ReceiveConfigurationParameters[7]}"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"rm -f /tmp/mtg_install.sh"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - sshShellCommand = @"if [ -f /usr/local/bin/mtg ];then echo '1';else echo '0'; fi"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string installResult = currentShellCommandResult; - - if (!installResult.Contains("1")) - { - //****** "安装失败,官方脚本运行出错!" ****** - MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString()); - //****** "安装失败,官方脚本运行出错!" ****** - currentStatus = Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - client.Disconnect(); - return; - } - else - { - //****** "MTProto安装成功!" ****** - SetUpProgressBarProcessing(61); - currentStatus = "MTProto" + Application.Current.FindResource("DisplayInstallInfo_SoftInstallSuccess").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - //设置开机自启动 - sshShellCommand = @"systemctl enable mtg"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - //sshShellCommand = @"mv /usr/local/etc/trojan/config.json /usr/local/etc/trojan/config.json.1"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //****** "安装完毕,上传配置文件......" ****** - //SetUpProgressBarProcessing(62); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadSoftConfig").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - - ////生成服务端配置 - ////serverConfig = @"/etc/shadowsocks.json"; - //string upLoadPath = @"/etc/shadowsocks.json"; - ////设置指向Caddy监听的随机端口 - ////Random random = new Random(); - //randomCaddyListenPort = GetRandomPort(); - //string randomSSRListenPortStr = randomCaddyListenPort.ToString(); - - //sshShellCommand = $"sed -i 's/8800/{randomSSRListenPortStr}/' {upLoadPath}"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////设置密码 - //sshShellCommand = $"sed -i 's/##password##/{ReceiveConfigurationParameters[2]}/' {upLoadPath}"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////****** "安装Caddy......" ****** - //SetUpProgressBarProcessing(65); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallCaddy").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - - ////安装Caddy - ////为假则表示系统有相应的组件。 - //if (getApt == false) - //{ - // sshShellCommand = @"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"apt install -y apt-transport-https"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"apt -qq update"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"apt -y -qq install caddy"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // SetUpProgressBarProcessing(74); - //} - //else if (getDnf == false) - //{ - - // sshShellCommand = @"dnf install 'dnf-command(copr)' -y"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"dnf copr enable @caddy/caddy -y"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //sshShellCommand = @"dnf -q makecache"; - // //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"dnf -y -q install caddy"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // SetUpProgressBarProcessing(74); - //} - //else if (getYum == false) - //{ - // sshShellCommand = @"yum install yum-plugin-copr -y"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"yum copr enable @caddy/caddy -y"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //sshShellCommand = @"yum -q makecache"; - // //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // sshShellCommand = @"yum -y -q install caddy"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // SetUpProgressBarProcessing(74); - //} - - //sshShellCommand = @"find / -name caddy"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //installResult = currentShellCommandResult; - - //if (!installResult.Contains("/usr/bin/caddy")) - //{ - // //****** "安装Caddy失败!" ****** - // MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString()); - // //****** "安装Caddy失败!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // client.Disconnect(); - // return; - //} - - ////****** "Caddy安装成功!" ****** - //SetUpProgressBarProcessing(75); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstalledCaddyOK").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - - //sshShellCommand = @"systemctl enable caddy"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////****** "上传Caddy配置文件......" ****** - //SetUpProgressBarProcessing(80); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfig").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - - //sshShellCommand = @"mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //string caddyConfig = @"TemplateConfg\ssr\ssr_tls.caddyfile"; - //upLoadPath = @"/etc/caddy/Caddyfile"; - - //UploadConfig(connectionInfo, caddyConfig, upLoadPath); - - ////设置Caddy监听的随机端口 - //string randomCaddyListenPortStr = randomCaddyListenPort.ToString(); - - //sshShellCommand = $"sed -i 's/8800/{randomCaddyListenPortStr}/' {upLoadPath}"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - - ////设置域名 - - //sshShellCommand = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}/g' {upLoadPath}"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////设置伪装网站 - //if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) - //{ - // sshShellCommand = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //} - ////****** "Caddy配置文件上传成功,OK!" ****** - //SetUpProgressBarProcessing(83); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_UploadCaddyConfigOK").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - - ////****** "正在启动Caddy......" ****** - //SetUpProgressBarProcessing(85); - //currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyService").ToString(); - //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - //currentShellCommandResult = currentStatus; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - ////Thread.Sleep(1000); - ////启动Caddy服务 - //sshShellCommand = @"systemctl restart caddy"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(3000); - - //sshShellCommand = @"ps aux | grep caddy"; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - //{ - // //****** "Caddy启动成功!" ****** - // SetUpProgressBarProcessing(89); - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //Thread.Sleep(1000); - //} - //else - //{ - // //****** "Caddy启动失败!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceFail").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // //Thread.Sleep(1000); - - // //****** "正在启动Caddy(第二次尝试)!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecond").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // //Thread.Sleep(1000); - // sshShellCommand = @"systemctl restart caddy"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // Thread.Sleep(3000); - - // sshShellCommand = @"ps aux | grep caddy"; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - // currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // if (currentShellCommandResult.Contains("/usr/bin/caddy") == true) - // { - // //****** "Caddy启动成功!" ****** - // SetUpProgressBarProcessing(89); - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceOK").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - // //Thread.Sleep(1000); - // } - // else - // { - // //****** "Caddy启动失败(第二次)!退出安装!" ****** - // currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartCaddyServiceSecondFail").ToString(); - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // currentShellCommandResult = currentStatus; - // TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - // //Thread.Sleep(1000); - - // //****** "Caddy启动失败,原因未知!请向开发者问询!" ****** - // MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_CaddyServiceFailedExit").ToString()); - // return; - // } - //} + //程序是否安装成功检测并设置开机启动 41--43 + functionResult = SoftInstalledSuccessOrFail(client, "mtg", @"/usr/local/bin/mtg"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } //****** "正在启动MTProto......" ****** - SetUpProgressBarProcessing(90); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoft").ToString() + "MTProto......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + SetUpProgressBarProcessing(80); + //currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoft").ToString() + "MTProto......"; + //MainWindowsShowInfo(currentStatus); - //Thread.Sleep(1000); //启动MTProto服务 - sshShellCommand = @"systemctl restart mtg"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep mtg"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("/usr/local/bin/mtg") == true) - { - //****** "MTProto启动成功!" ****** - SetUpProgressBarProcessing(93); - currentStatus = "MTProto" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "MTProto启动失败!" ****** - currentStatus = "MTProto" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - - //****** "正在第二次尝试启动MTProto!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoftSecond").ToString() + "MTProto!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - Thread.Sleep(3000); - sshShellCommand = @"systemctl restart mtg"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - Thread.Sleep(3000); - - sshShellCommand = @"ps aux | grep mtg"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - if (currentShellCommandResult.Contains("usr/bin/ssr") == true) - { - //****** "MTProto启动成功!" ****** - SetUpProgressBarProcessing(93); - currentStatus = "MTProto" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - } - else - { - //****** "MTProto启动失败(第二次)!退出安装!" ****** - currentStatus = "MTProto" + Application.Current.FindResource("DisplayInstallInfo_StartSoftSecondFail").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - //Thread.Sleep(1000); - - //****** "MTProto启动失败,原因未知!请向开发者问询!" ****** - MessageBox.Show("MTProto" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFailedExit").ToString()); - return; - } - } + functionResult = SoftStartDetect(client, "mtg", @"/usr/local/bin/mtg"); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } - //测试BBR条件,若满足则启用 - //****** "BBR测试......" ****** - SetUpProgressBarProcessing(94); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"uname -r"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - string[] linuxKernelVerStr = currentShellCommandResult.Split('-'); - - bool detectResult = DetectKernelVersionBBR(linuxKernelVerStr[0]); - - sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - string resultCmdTestBBR = currentShellCommandResult; - //如果内核满足大于等于4.9,且还未启用BBR,则启用BBR - if (detectResult == true && resultCmdTestBBR.Contains("bbr") == false) - { - //****** "正在启用BBR......" ****** - SetUpProgressBarProcessing(95); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableBBR").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); - - sshShellCommand = @"bash -c 'echo ""net.core.default_qdisc=fq"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"bash -c 'echo ""net.ipv4.tcp_congestion_control=bbr"" >> /etc/sysctl.conf'"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - sshShellCommand = @"sysctl -p"; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 - currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else if (resultCmdTestBBR.Contains("bbr") == true) - { - //****** "BBR已经启用了!" ****** - SetUpProgressBarProcessing(97); - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRisEnabled").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - else - { - //****** "系统不满足启用BBR的条件,启用失败!" ****** - currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - } - + //检测BBR,满足条件并启动 90--95 + functionResult = DetectBBRandEnable(client); + if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + //****** "生成客户端配置......" ****** - SetUpProgressBarProcessing(98); + SetUpProgressBarProcessing(96); currentStatus = Application.Current.FindResource("DisplayInstallInfo_GenerateClientConfig").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); //读取生成的代理参数 sshShellCommand = @"cat /usr/local/etc/mtg_info.json"; currentShellCommandResult = client.RunCommand(sshShellCommand).Result; @@ -12365,11 +9193,7 @@ namespace ProxySU //****** "MTProto+TLS安装成功,祝你玩的愉快!!" ****** SetUpProgressBarProcessing(100); currentStatus = "MTProto+TLS" + Application.Current.FindResource("DisplayInstallInfo_ProxyInstalledOK").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - - //Thread.Sleep(1000); + MainWindowsShowInfo(currentStatus); //显示服务端连接参数 proxyType = "MTProto"; @@ -12384,16 +9208,43 @@ namespace ProxySU { ProcessException(ex1.Message); - //****** "主机登录失败!" ****** + //****** "安装失败!" ****** currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginFailed").ToString(); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - currentShellCommandResult = currentStatus; - TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 - + MainWindowsShowInfo(currentStatus); } #endregion } + + //下载安装脚本安装MTProto 37--40 + //functionResult = MTProtoInstall(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool MTProtoInstall(SshClient client) + { + //****** "系统环境检测完毕,符合安装要求,开始布署......" ****** + SetUpProgressBarProcessing(37); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstalling").ToString(); + MainWindowsShowInfo(currentStatus); + + //下载安装脚本安装 + //****** "正在安装MTProto......" ****** + SetUpProgressBarProcessing(38); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallSoft").ToString() + "MTProto......"; + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"curl -o /tmp/mtg_install.sh https://raw.githubusercontent.com/proxysu/shellscript/master/MTProto/mtg_install.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"yes | bash /tmp/mtg_install.sh {ReceiveConfigurationParameters[1]} {ReceiveConfigurationParameters[7]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"rm -f /tmp/mtg_install.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + SetUpProgressBarProcessing(40); + + return true; + } #endregion @@ -13512,13 +10363,13 @@ namespace ProxySU //sshShellCommand = @"command -v systemctl"; //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //bool getSystemd = String.IsNullOrEmpty(currentShellCommandResult); //sshShellCommand = @"command -v getenforce"; //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 //currentShellCommandResult = client.RunCommand(sshShellCommand).Result; - //TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + //bool getGetenforce = String.IsNullOrEmpty(currentShellCommandResult); @@ -13782,13 +10633,6 @@ namespace ProxySU #endregion - private void Button_Click(object sender, RoutedEventArgs e) - { - //显示服务端连接参数 - proxyType = "Trojan"; - ResultClientInformation resultClientInformation = new ResultClientInformation(); - resultClientInformation.ShowDialog(); - } #region 三合一安装过程 @@ -14775,7 +11619,977 @@ namespace ProxySU #endregion + #region 测试用代码 + private void Button_Click(object sender, RoutedEventArgs e) + { + ConnectionInfo connectionInfo = GenerateConnectionInfo(); + if (connectionInfo == null) + { + //****** "远程主机连接信息有误,请检查!" ****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorHostConnection").ToString()); + return; + } + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + SoftInstalledSuccessOrFail(client, "v2ray", @"/usr/local/bin/v2ray"); + //CaddyInstall(client); + //if (client.IsConnected == true) + //{ + // MessageBox.Show("Connected"); + //} + //if (client.IsConnected == false) + //{ + // MessageBox.Show("disConnected"); + //} + } + } + + private string CaddyInstallTest(SshClient client) + { + + if (client.IsConnected == true) + { + //******"主机登录成功"****** + SetUpProgressBarProcessing(3); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_LoginSuccessful").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"id -u"; + MainWindowsShowCmd(client, sshShellCommand); + + client.Disconnect(); + } + return ""; + } + #endregion + + #region 布署代理所用到的步骤函数 + + #region 安装过程提示信息 + + //安装过程提示信息 + // MainWindowsShowInfo(currentStatus); + // currentShellCommandResult = MainWindowsShowCmd(client,sshShellCommand); + private string MainWindowsShowInfo(string currentStatus) + { + TextBlockSetUpProcessing.Dispatcher.BeginInvoke(updateAction, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, currentStatus); + string currentShellCommandResult = currentStatus; + TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果在监视窗口 + + return currentShellCommandResult; + } + + //安装过程所运行的命令与相应结果 + private string MainWindowsShowCmd(SshClient client,string sshShellCommand) + { + TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, sshShellCommand);//显示执行的命令 + string currentShellCommandResult = client.RunCommand(sshShellCommand).Result; + TextBoxMonitorCommandResults.Dispatcher.BeginInvoke(updateMonitorAction, TextBoxMonitorCommandResults, currentShellCommandResult);//显示命令执行的结果 + + return currentShellCommandResult; + } + + //调用的函数返回false后的提示 + private string FunctionResultErr() + { + string currentStatus = Application.Current.FindResource("DisplayInstallInfo_FunctionResultErr").ToString(); + MainWindowsShowInfo(currentStatus); + return ""; + } + #endregion + + //TextBoxMonitorCommandResults.Text = ""; + //functionResult = true; + //getApt = false; + //getDnf = false; + //getYum = false; + + //检测root权限 5--7 + //functionResult = RootAuthorityDetect(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool RootAuthorityDetect(SshClient client) + { + //******"检测是否运行在root权限下..."******01 + SetUpProgressBarProcessing(5); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootPermission").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"id -u"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //string testRootAuthority = currentShellCommandResult; + if (currentShellCommandResult.Equals("0\n") == false) + { + //******"请使用具有root权限的账户登录主机!!"****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorRootPermission").ToString()); + //client.Disconnect(); + return false; + } + else + { + //******"检测结果:OK!"******02 + SetUpProgressBarProcessing(7); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_DetectionRootOK").ToString(); + MainWindowsShowInfo(currentStatus); + //return true; + } + return true; + } + + //检测是否已安装代理 8--10 + //soft--要检测的程序 + //condition---已安装的条件 + //functionResult = SoftInstalledIsNoYes(client, "v2ray", @"/usr/local/bin/v2ray"); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool SoftInstalledIsNoYes(SshClient client,string soft,string condition) + { + //******"检测系统是否已经安装......"******03 + SetUpProgressBarProcessing(8); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestExistSoft").ToString() + $"{soft}......"; + MainWindowsShowInfo(currentStatus); + + + sshShellCommand = $"find / -name {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //string resultCmdTestV2rayInstalled = currentShellCommandResult; + if (currentShellCommandResult.Contains($"{condition}") == true) + { + //******"远程主机已安装V2ray,是否强制重新安装?"****** + string messageShow = Application.Current.FindResource("MessageBoxShow_ExistedSoft").ToString() + + $"{soft}" + + Application.Current.FindResource("MessageBoxShow_ForceInstallSoft").ToString(); + MessageBoxResult messageBoxResult = MessageBox.Show(messageShow, "", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (messageBoxResult == MessageBoxResult.No) + { + //******"安装取消,退出"****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstallationCanceledExit").ToString(); + MainWindowsShowInfo(currentStatus); + //client.Disconnect(); + return false; + } + else + { + //******"已选择强制安装!"******04 + SetUpProgressBarProcessing(10); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ForceInstallSoft").ToString() + $"{soft}"; + MainWindowsShowInfo(currentStatus); + + } + } + else + { + //******"检测结果:未安装"******04 + SetUpProgressBarProcessing(10); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_NoInstalledSoft").ToString() + $"{soft}"; + MainWindowsShowInfo(currentStatus); + } + return true; + } + + //检测关闭Selinux及系统组件是否齐全(apt/yum/dnf/systemctl)11--30 + //安装依赖软件,检测端口,防火墙开启端口 + //functionResult = ShutDownSelinuxAndSysComponentsDetect(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool ShutDownSelinuxAndSysComponentsDetect(SshClient client) + { + //检测系统是否支持yum 或 apt或zypper,且支持Systemd + //如果不存在组件,则命令结果为空,String.IsNullOrEmpty值为真 + //取反则getApt,getDnf,getYum,getSystem,getGetenforce为假 + //不存在组件,则为假 + + //******"检测系统是否符合安装要求......"****** + SetUpProgressBarProcessing(11); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_CheckSystemRequirements").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"command -v apt"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + getApt = ! String.IsNullOrEmpty(currentShellCommandResult); + + sshShellCommand = @"command -v dnf"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + getDnf = ! String.IsNullOrEmpty(currentShellCommandResult); + + sshShellCommand = @"command -v yum"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + getYum = ! String.IsNullOrEmpty(currentShellCommandResult); + + SetUpProgressBarProcessing(13); + + //sshShellCommand = @"command -v zypper"; + //currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + //bool getZypper = ! String.IsNullOrEmpty(currentShellCommandResult); + + sshShellCommand = @"command -v systemctl"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + bool getSystemd = ! String.IsNullOrEmpty(currentShellCommandResult); + + sshShellCommand = @"command -v getenforce"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + bool getGetenforce = ! String.IsNullOrEmpty(currentShellCommandResult); + + + //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 + //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 + if ((getApt == false && getDnf == false && getYum == false) || getSystemd == false) + { + //******"系统缺乏必要的安装组件如:apt||dnf||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_MissingSystemComponents").ToString()); + + //******"系统环境不满足要求,安装失败!!"****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_MissingSystemComponents").ToString(); + MainWindowsShowInfo(currentStatus); + + return false; + } + else + { + //******"检测结果:OK!"******06 + SetUpProgressBarProcessing(16); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_SystemRequirementsOK").ToString(); + MainWindowsShowInfo(currentStatus); + } + + //设置安装软件所用的命令格式 + if (getApt == true) + { + sshCmdUpdate = @"apt -qq update"; + sshCmdInstall = @"apt -y -qq install "; + } + else if (getDnf == true) + { + sshCmdUpdate = @"dnf -q makecache"; + sshCmdInstall = @"dnf -y -q install "; + } + else if (getYum == true) + { + sshCmdUpdate = @"yum -q makecache"; + sshCmdInstall = @"yum -y -q install "; + } + //else if (getZypper == true) + //{ + // sshCmdUpdate = @"zypper ref"; + // sshCmdInstall = @"zypper -y install "; + //} + + //判断是否启用了SELinux,如果启用了,并且工作在Enforcing模式下,则改为Permissive模式 + if (getGetenforce == true) + { + sshShellCommand = @"getenforce"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + //string testSELinux = currentShellCommandResult; + + if (currentShellCommandResult.Contains("Enforcing") == true) + { + //******"检测到系统启用SELinux,且工作在严格模式下,需改为宽松模式!修改中......"******07 + SetUpProgressBarProcessing(18); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableSELinux").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"setenforce 0"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //******"修改完毕!"******08 + SetUpProgressBarProcessing(20); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_SELinuxModifyOK").ToString(); + MainWindowsShowInfo(currentStatus); + } + + } + + //在相应系统内安装curl(如果没有安装curl)--此为依赖软件 + if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) + { + sshShellCommand = $"{sshCmdUpdate}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"{sshCmdInstall}curl"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + // 在相应系统内安装wget(如果没有安装wget)--此为依赖软件 + if (string.IsNullOrEmpty(client.RunCommand("command -v wget").Result) == true) + { + sshShellCommand = $"{sshCmdUpdate}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"{sshCmdInstall}wget"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + // 在相应系统内安装unzip(如果没有安装unzip)--此为依赖软件 + if (string.IsNullOrEmpty(client.RunCommand("command -v unzip").Result) == true) + { + sshShellCommand = $"{sshCmdUpdate}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"{sshCmdInstall}unzip"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + //检测是否安装lsof + if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) + { + sshShellCommand = $"{sshCmdUpdate}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"{sshCmdInstall}lsof"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + //****** "检测端口占用情况......" ****** + SetUpProgressBarProcessing(22); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestPortUsed").ToString(); + MainWindowsShowInfo(currentStatus); + + if (String.Equals(ReceiveConfigurationParameters[1], "80") == true || String.Equals(ReceiveConfigurationParameters[1], "443") == true) + { + string testPort80 = string.Empty; + string testPort443 = string.Empty; + + sshShellCommand = @"lsof -n -P -i :80 | grep LISTEN"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + testPort80 = currentShellCommandResult; + + sshShellCommand = @"lsof -n -P -i :443 | grep LISTEN"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + testPort443 = currentShellCommandResult; + + + if (String.IsNullOrEmpty(testPort80) == false || String.IsNullOrEmpty(testPort443) == false) + { + //****** "80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?" ****** + MessageBoxResult dialogResult = MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorPortUsed").ToString(), "Stop application", MessageBoxButton.YesNo); + if (dialogResult == MessageBoxResult.No) + { + //****** "端口被占用,安装失败......" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorPortUsedFail").ToString(); + MainWindowsShowInfo(currentStatus); + //client.Disconnect(); + return false; + } + + //****** "正在释放80/443端口......" ****** + SetUpProgressBarProcessing(24); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePort").ToString(); + MainWindowsShowInfo(currentStatus); + + if (String.IsNullOrEmpty(testPort443) == false) + { + string[] cmdResultArry443 = testPort443.Split(' '); + + sshShellCommand = $"systemctl stop {cmdResultArry443[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"systemctl disable {cmdResultArry443[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"kill -9 {cmdResultArry443[3]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + + if (String.IsNullOrEmpty(testPort80) == false) + { + string[] cmdResultArry80 = testPort80.Split(' '); + + sshShellCommand = $"systemctl stop {cmdResultArry80[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"systemctl disable {cmdResultArry80[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"kill -9 {cmdResultArry80[3]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + //****** "80/443端口释放完毕!" ****** + SetUpProgressBarProcessing(26); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOK").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "检测结果:未被占用!" ****** + SetUpProgressBarProcessing(26); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_PortNotUsed").ToString(); + MainWindowsShowInfo(currentStatus); + } + } + else + { + string testPort = string.Empty; + + sshShellCommand = $"lsof -n -P -i :{ReceiveConfigurationParameters[1]} | grep LISTEN"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + testPort = currentShellCommandResult; + + if (String.IsNullOrEmpty(testPort) == false) + { + //****** "端口被占用,将强制停止占用此端口的程序?" ****** + MessageBoxResult dialogResult = MessageBox.Show(ReceiveConfigurationParameters[1] + Application.Current.FindResource("MessageBoxShow_ErrorPortUsedOther").ToString(), "Stop application", MessageBoxButton.YesNo); + if (dialogResult == MessageBoxResult.No) + { + //****** "端口被占用,安装失败......" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorPortUsedFail").ToString(); + MainWindowsShowInfo(currentStatus); + //client.Disconnect(); + return false; + } + + //****** "正在释放端口......" ****** + SetUpProgressBarProcessing(24); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOther").ToString(); + MainWindowsShowInfo(currentStatus); + + string[] cmdResultArry = testPort.Split(' '); + + sshShellCommand = $"systemctl stop {cmdResultArry[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"systemctl disable {cmdResultArry[0]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"kill -9 {cmdResultArry[3]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //****** "端口释放完毕!" ****** + SetUpProgressBarProcessing(26); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ReleasePortOKOther").ToString(); + MainWindowsShowInfo(currentStatus); + + } + else + { + //****** "检测结果:未被占用!" ****** + SetUpProgressBarProcessing(26); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_PortNotUsed").ToString(); + MainWindowsShowInfo(currentStatus); + } + } + //****** "开启防火墙相应端口......" ****** + SetUpProgressBarProcessing(27); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_OpenFireWallPort").ToString(); + MainWindowsShowInfo(currentStatus); + string openFireWallPort = ReceiveConfigurationParameters[1]; + if (String.IsNullOrEmpty(client.RunCommand("command -v firewall-cmd").Result) == false) + { + if (String.Equals(openFireWallPort, "443")) + { + sshShellCommand = @"firewall-cmd --zone=public --add-port=80/tcp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"firewall-cmd --zone=public --add-port=80/udp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"firewall-cmd --zone=public --add-port=443/tcp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"firewall-cmd --zone=public --add-port=443/udp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | firewall-cmd --reload"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + else + { + sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/tcp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"firewall-cmd --zone=public --add-port={openFireWallPort}/udp --permanent"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | firewall-cmd --reload"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + } + else if (String.IsNullOrEmpty(client.RunCommand("command -v ufw").Result) == false) + { + if (String.Equals(openFireWallPort, "443")) + { + sshShellCommand = @"ufw allow 80/tcp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"ufw allow 80/udp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"ufw allow 443/tcp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"ufw allow 443/udp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | ufw reload"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + else + { + sshShellCommand = $"ufw allow {openFireWallPort}/tcp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"ufw allow {openFireWallPort}/udp"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yes | ufw reload"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + } + SetUpProgressBarProcessing(30); + return true; + } + + //检测校对时间 31--33 + //functionResult = CheckProofreadingTime(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool CheckProofreadingTime(SshClient client) + { + //******"校对时间......"******09 + SetUpProgressBarProcessing(31); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ProofreadingTime").ToString(); + MainWindowsShowInfo(currentStatus); + + //获取远程主机的时间戳 + long timeStampVPS = Convert.ToInt64(client.RunCommand("date +%s").Result.ToString()); + + //获取本地时间戳 + TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0); + long timeStampLocal = Convert.ToInt64(ts.TotalSeconds); + if (Math.Abs(timeStampLocal - timeStampVPS) >= 90) + { + //******"本地时间与远程主机时间相差超过限制(90秒),请先用 '系统工具-->时间校对' 校对时间后再设置"****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_TimeError").ToString()); + //"时间较对失败......" + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TimeError").ToString(); + MainWindowsShowInfo(currentStatus); + + //client.Disconnect(); + return false; + } + //******"时间差符合要求,OK!"******10 + SetUpProgressBarProcessing(33); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TimeOK").ToString(); + MainWindowsShowInfo(currentStatus); + return true; + } + + //检测域名是否解析到当前IP上 34---36 + //functionResult = DomainResolutionCurrentIPDetect(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool DomainResolutionCurrentIPDetect(SshClient client) + { + //****** "正在检测域名是否解析到当前VPS的IP上......" ******11 + SetUpProgressBarProcessing(34); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestDomainResolve").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"curl -4 ip.sb"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + string nativeIp = currentShellCommandResult; + + sshShellCommand = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + string resultTestDomainCmd = currentShellCommandResult; + if (String.Equals(nativeIp, resultTestDomainCmd) == true) + { + //****** "解析正确!OK!" ******12 + SetUpProgressBarProcessing(36); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_DomainResolveOK").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "域名未能正确解析到当前VPS的IP上!安装失败!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorDomainResolve").ToString(); + MainWindowsShowInfo(currentStatus); + + //****** "域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!" ****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorDomainResolve").ToString()); + //client.Disconnect(); + return false; + } + return true; + } + + + //安装代理程序 37--40 + + + //程序是否安装成功检测并设置开机启动 41--43 + //soft--要检测的程序 + //condition---成功安装的条件 + //functionResult = SoftInstalledSuccessOrFail(client,"v2ray",@"/usr/local/bin/v2ray"); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool SoftInstalledSuccessOrFail(SshClient client,string soft,string condition) + { + SetUpProgressBarProcessing(41); + sshShellCommand = $"find / -name {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (!currentShellCommandResult.Contains($"{condition}")) + { + //****** "安装失败,官方脚本运行出错!" ****** + MessageBox.Show(Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString()); + //****** "安装失败,官方脚本运行出错!" ****** + currentStatus = Application.Current.FindResource("MessageBoxShow_ErrorInstallSoftFail").ToString(); + MainWindowsShowInfo(currentStatus); + + //client.Disconnect(); + return false; + } + else + { + //****** "安装成功!" ******20 + SetUpProgressBarProcessing(43); + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_SoftInstallSuccess").ToString(); + MainWindowsShowInfo(currentStatus); + + //开机启动 + sshShellCommand = $"systemctl enable {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + } + return true; + } + + + //生成服务端配置 44--46 + //functionResult = GenerateServerConfiguration(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + + //上传服务配置 47--50 + + + //acme.sh安装与申请证书 51--57 + //functionResult = AcmeShInstall(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool AcmeShInstall(SshClient client) + { + + //****** "正在安装acme.sh......" ******22 + SetUpProgressBarProcessing(51); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallAcmeSh").ToString(); + MainWindowsShowInfo(currentStatus); + + //安装所依赖的软件 + sshShellCommand = $"{sshCmdUpdate}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = $"{sshCmdInstall}socat"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //解决搬瓦工CentOS缺少问题 + sshShellCommand = $"{sshCmdInstall}automake autoconf libtool"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains("Install success") == true) + { + //****** "acme.sh安装成功!" ******23 + SetUpProgressBarProcessing(54); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_AcmeShInstallSuccess").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "acme.sh安装失败!原因未知,请向开发者提问!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorAcmeShInstallFail").ToString(); + MainWindowsShowInfo(currentStatus); + return false; + } + + sshShellCommand = @"cd ~/.acme.sh/"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"alias acme.sh=~/.acme.sh/acme.sh"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //****** "申请域名证书......" ******24 + SetUpProgressBarProcessing(55); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartApplyCert").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = $"/root/.acme.sh/acme.sh --force --issue --standalone -d {ReceiveConfigurationParameters[4]}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains("Cert success") == true) + { + //****** "证书申请成功!" ******25 + SetUpProgressBarProcessing(57); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertSuccess").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "证书申请失败!原因未知,请向开发者提问!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ApplyCertFail").ToString(); + MainWindowsShowInfo(currentStatus); + return false; + } + return true; + + } + + + + //安装证书到代理程序 58--60 + + + + //Caddy安装 61--66 + //functionResult = CaddyInstall(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool CaddyInstall(SshClient client) + { + //****** "安装Caddy......" ******28 + SetUpProgressBarProcessing(61); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartInstallCaddy").ToString(); + MainWindowsShowInfo(currentStatus); + + //为真则表示系统有相应的组件。 + if (getApt == true) + { + + sshShellCommand = @"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"apt install -y apt-transport-https"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"apt -qq update"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"apt -y -qq install caddy"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + else if (getDnf == true) + { + + sshShellCommand = @"dnf install 'dnf-command(copr)' -y"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"dnf copr enable @caddy/caddy -y"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //sshShellCommand = @"dnf -q makecache"; + //currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"dnf -y -q install caddy"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + else if (getYum == true) + { + + sshShellCommand = @"yum install yum-plugin-copr -y"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"yum copr enable @caddy/caddy -y"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //sshShellCommand = @"yum -q makecache"; + //currentShellCommandResult = MainWindowsShowCmd(client,sshShellCommand); + + sshShellCommand = @"yum -y -q install caddy"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + } + + sshShellCommand = @"find / -name caddy"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (!currentShellCommandResult.Contains("/usr/bin/caddy")) + { + //****** "安装Caddy失败!" ****** + MessageBox.Show(Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString()); + //****** "安装Caddy失败!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_ErrorInstallCaddyFail").ToString(); + MainWindowsShowInfo(currentStatus); + + //client.Disconnect(); + return false; + } + //****** "Caddy安装成功!" ******29 + SetUpProgressBarProcessing(66); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_InstalledCaddyOK").ToString(); + MainWindowsShowInfo(currentStatus); + + + sshShellCommand = @"systemctl enable caddy"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + return true; + } + + + //上传Caddy配置文件67--70 + + + //程序启动检测 + //soft--要检测的程序 + //condition---成功启动的条件 + //functionResult = SoftStartDetect(client, "v2ray", @"/usr/local/bin/v2ray"); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool SoftStartDetect(SshClient client,string soft,string condition) + { + //****** "正在启动......" ******33 + //SetUpProgressBarProcessing(87); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoft").ToString() + $"{soft}......"; + MainWindowsShowInfo(currentStatus); + + //启动服务 + sshShellCommand = $"systemctl restart {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + Thread.Sleep(3000); + + sshShellCommand = $"ps aux | grep {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains($"{condition}") == true) + { + //****** "启动成功!" ******34 + //SetUpProgressBarProcessing(88); + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); + MainWindowsShowInfo(currentStatus); + + } + else + { + //****** "启动失败!" ****** + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFail").ToString(); + MainWindowsShowInfo(currentStatus); + + Thread.Sleep(1000); + + //****** "正在启动(第二次尝试)!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_StartSoftSecond").ToString() + $"{soft}"; + MainWindowsShowInfo(currentStatus); + + Thread.Sleep(3000); + sshShellCommand = $"systemctl restart {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + Thread.Sleep(3000); + + sshShellCommand = $"ps aux | grep {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains($"{condition}") == true) + { + //****** "启动成功!" ****** + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftOK").ToString(); + MainWindowsShowInfo(currentStatus); + + } + else + { + //****** "启动失败(第二次)!退出安装!" ****** + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftSecondFail").ToString(); + MainWindowsShowInfo(currentStatus); + + //显示启动失败原因 + sshShellCommand = $"journalctl -n50 --no-pager --boot -u {soft}"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + //****** "启动失败,原因如上!请排查原因!" ****** + currentStatus = $"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFailedExit").ToString(); + MainWindowsShowInfo(currentStatus); + + //****** "启动失败,原因如上!请排查原因!" ****** + MessageBox.Show($"{soft}" + Application.Current.FindResource("DisplayInstallInfo_StartSoftFailedExit").ToString()); + return false; + } + } + return true; + } + + //检测BBR,满足条件并启动 90--95 + //functionResult = DetectBBRandEnable(client); + //if (functionResult == false) { FunctionResultErr(); client.Disconnect(); return; } + private bool DetectBBRandEnable(SshClient client) + { + //测试BBR条件,若满足提示是否启用 + //****** "BBR测试......" ******37 + SetUpProgressBarProcessing(90); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_TestBBR").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"uname -r"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + string[] linuxKernelVerStrBBR = currentShellCommandResult.Split('-'); + + bool detectResultBBR = DetectKernelVersionBBR(linuxKernelVerStrBBR[0]); + + sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + string resultCmdTestBBR = currentShellCommandResult; + //如果内核满足大于等于4.9,且还未启用BBR,则启用BBR + if (detectResultBBR == true && resultCmdTestBBR.Contains("bbr") == false) + { + //****** "正在启用BBR......" ******38 + SetUpProgressBarProcessing(93); + currentStatus = Application.Current.FindResource("DisplayInstallInfo_EnableBBR").ToString(); + MainWindowsShowInfo(currentStatus); + + sshShellCommand = @"bash -c 'echo ""net.core.default_qdisc=fq"" >> /etc/sysctl.conf'"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"bash -c 'echo ""net.ipv4.tcp_congestion_control=bbr"" >> /etc/sysctl.conf'"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"sysctl -p"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + sshShellCommand = @"sysctl net.ipv4.tcp_congestion_control | grep bbr"; + currentShellCommandResult = MainWindowsShowCmd(client, sshShellCommand); + + if (currentShellCommandResult.Contains("bbr") == true) + { + //****** "BBR启用成功!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBREnabledSuccess").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "系统不满足启用BBR的条件,启用失败!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); + MainWindowsShowInfo(currentStatus); + return false; + } + } + else if (resultCmdTestBBR.Contains("bbr") == true) + { + //****** "BBR已经启用了!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRisEnabled").ToString(); + MainWindowsShowInfo(currentStatus); + } + else + { + //****** "系统不满足启用BBR的条件,启用失败!" ****** + currentStatus = Application.Current.FindResource("DisplayInstallInfo_BBRFailed").ToString(); + MainWindowsShowInfo(currentStatus); + return false; + } + SetUpProgressBarProcessing(95); + return true; + } + + + //生成客户端配置 96--98 + + + #endregion + } } diff --git a/ProxySU/Properties/AssemblyInfo.cs b/ProxySU/Properties/AssemblyInfo.cs index 9c8497e..ae9a2d9 100644 --- a/ProxySU/Properties/AssemblyInfo.cs +++ b/ProxySU/Properties/AssemblyInfo.cs @@ -51,5 +51,5 @@ using System.Windows; // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.4.1.0")] -[assembly: AssemblyFileVersion("2.4.1.0")] +[assembly: AssemblyVersion("2.4.3.0")] +[assembly: AssemblyFileVersion("2.4.3.0")] diff --git a/ProxySU/Translations/ProxySU.en-US.xaml b/ProxySU/Translations/ProxySU.en-US.xaml index e7e7dc4..fac7b85 100644 --- a/ProxySU/Translations/ProxySU.en-US.xaml +++ b/ProxySU/Translations/ProxySU.en-US.xaml @@ -226,12 +226,14 @@ T.ME format URL (double-click to copy to the clipboard) Host address, host port, and user name are required and cannot be empty!! + The connection port contains non-numeric characters! The login password is required and cannot be empty!! The key file is required and cannot be empty!! If a proxy is selected, the proxy address and port cannot be empty! If the proxy needs to log in, the user name and password for proxy login cannot be empty! The remote host connection information is wrong, please check! Please select a configuration template first! + An error occurred, the installation was interrupted... Logging in to the remote host... The host login is successful! Detect whether it is running under root permissions... @@ -265,6 +267,9 @@ The port is occupied and the installation failed... is releasing port 80/443... The release of port 80/443 is complete! + The port is occupied, will the program occupying this port be forcibly stopped? + Release the port... + The port is released! Test result: Not occupied! The system environment has been tested and the installation requirements are met, and the deployment begins... Open the corresponding port of the firewall... @@ -301,7 +306,7 @@ Startup failed! is trying to start the second time failed to start (second time)! Exit the installation! - Start failed, the reason is unknown! Please ask the developer! + Startup failed, the reason is as above! Please troubleshoot the reason! BBR test... Enable BBR... BBR has been enabled! @@ -309,7 +314,7 @@ BBR is successfully activated! Generate client configuration... The installation is successful, Enjoy it!! - Host login failed! + Installation Failed! An error occurred! Wrong password or wrong username! Please check whether the host address and port are correct, if it passes the proxy, please check whether the proxy is working properly diff --git a/ProxySU/Translations/ProxySU.zh-CN.xaml b/ProxySU/Translations/ProxySU.zh-CN.xaml index ee51459..e27655f 100644 --- a/ProxySU/Translations/ProxySU.zh-CN.xaml +++ b/ProxySU/Translations/ProxySU.zh-CN.xaml @@ -235,12 +235,14 @@ 主机地址、主机端口、用户名为必填项,不能为空!! + 连接端口含有非数字字符! 登录密码为必填项,不能为空!! 密钥文件为必填项,不能为空!! 如果选择了代理,则代理地址与端口不能为空! 如果代理需要登录,则代理登录的用户名与密码不能为空! 远程主机连接信息有误,请检查! 请先选择配置模板! + 发生错误,安装中断...... 正在登录远程主机...... 主机登录成功! 检测是否运行在root权限下... @@ -274,6 +276,9 @@ 端口被占用,安装失败...... 正在释放80/443端口...... 80/443端口释放完毕! + 端口被占用,将强制停止占用此端口的程序? + 正在释放端口...... + 端口释放完毕! 检测结果:未被占用! 系统环境检测完毕,符合安装要求,开始布署...... 开启防火墙相应端口...... @@ -310,7 +315,7 @@ 启动失败! 正在第二次尝试启动 启动失败(第二次)!退出安装! - 启动失败,原因未知!请向开发者问询! + 启动失败,原因如上!请排查原因! BBR测试...... 正在启用BBR...... BBR已经启用了! @@ -318,7 +323,7 @@ BBR 启用成功! 生成客户端配置...... 安装成功,祝你玩的愉快!! - 主机登录失败! + 安装失败! 发生错误! 密码错误或用户名错误! 请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作 diff --git a/ProxySU/Translations/ProxySU.zh-TW.xaml b/ProxySU/Translations/ProxySU.zh-TW.xaml index a6b3585..2f1ec92 100644 --- a/ProxySU/Translations/ProxySU.zh-TW.xaml +++ b/ProxySU/Translations/ProxySU.zh-TW.xaml @@ -228,12 +228,14 @@ T.ME格式URL(雙擊複製到剪切板中) 主機地址、主機端口、用戶名為必填項,不能為空!! + 連接端口含有非數字字符! 登錄密碼為必填項,不能為空!! 密鑰文件為必填項,不能為空!! 如果選擇了代理,則代理地址與端口不能為空! 如果代理需要登錄,則代理登錄的用戶名與密碼不能為空! 遠程主機連接信息有誤,請檢查! 請先選擇配置模板! + 發生錯誤,安裝中斷...... 正在登錄遠程主機...... 主機登錄成功! 檢測是否運行在root權限下... @@ -267,6 +269,9 @@ 端口被佔用,安裝失敗...... 正在釋放80/443端口...... 80/443端口釋放完畢! + 端口被佔用,將強制停止佔用此端口的程序? + 正在釋放端口...... + 端口釋放完畢! 檢測結果:未被佔用! 系統環境檢測完畢,符合安裝要求,開始佈署...... 開啟防火牆相應端口...... @@ -303,7 +308,7 @@ 啟動失敗! 正在第二次嘗試啟動 啟動失敗(第二次)!退出安裝! - 啟動失敗,原因未知!請向開發者問詢! + 啟動失敗,原因如上!請排查原因! BBR測試...... 正在啟用BBR...... BBR已經啟用了! @@ -311,7 +316,7 @@ BBR 啟用成功! 生成客戶端配置...... 安裝成功,祝你玩的愉快! ! - 主機登錄失敗! + 安裝失敗! 發生錯誤! 密碼錯誤或用戶名錯誤! 請檢查主機地址及端口是否正確,如果通過代理,請檢查代理是否正常工作 diff --git a/ProxySU/bin/Beta/Beta.zip b/ProxySU/bin/Beta/Beta.zip index 97dd6ae5bd56a53727239eb025239a7813e49031..b4717d8172c572639a4197c8b72fdae3cfd1dff0 100644 GIT binary patch delta 122450 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

ppEhnltr`c}l160Gtcs_1b z(hPy`n36+7sCioiFZswB?H75LRb(5?qSqAqzakV4-eIC!O7(1gv z*mUt;{r)DICe*Z!d@lX4AeG^p3GTBSAhq8qWI4{tnte>m>;nj!9`-F-|1ngBuEi3{ ztR%B_tYk0Up4~|6U2ZKcfX17TRHEf7J9PIILin6aBg7bSRd>y4aBzdnMaLX*4RH0w z1uK8rAaWK7TSr#z#}8T#C;rt*^(LqBK4Q_O`zh_FDOXzftr-fg{!dt9Q1u55SYXl5 z@!8acPkF{SuNgq{3zIp(bBf?r^JsT~{+-1RT`3^3!Aj{-c*z(tQLcm94|?hzKo*pr zG?Cp5Wgfz~(YHCL^9fswSC`lP?yZ4dQF6au)+}fBpV? z?rYaN1x*T;RgSi_;^QZLkV9n;GC40njK(jSOja=G=a17eA%pZI) zwLpXMJ^z#g^BAeTQe=ze^=fJZ)bI}z_tC|wLP4u9$6HJp?#L{qAi+m-en4GFUD0>C z(>VjDJyF1)RJ(2+k5d0Kt(HXfg{^fAqKrgc{AZnal4=GIzIK#H7+2r&a&8Wz5$Ik*xSO>bY z(M>w7tl3pS$O@Ke=iq+W(g9MTw#L0c>4FamH)R0hdirn>^5QL)jv-(C(B8gI^`%7J zagqzQ8lkcrjTuqf07qq7EdzfN+ z!vT0(zcLdy%K|+RsU;gaSm}Psbv|^*L2t9xRCFna$T)A`C<^pSstj6a%9UxJUC?Pc z?m5Hu1rv}{a@}G+zMvSw!J+?coIY;tk^wnRC+J6_CpkbV^y6}M1IlWY#9Z&|=&Sf} zBNITe9>|HPX$_L9B^vC2W7A2jQDCoEM*&(Dnc9ek@MJQVJxJy*lH{k=M1>QRq7XfB z|1JpeI<-Z;mhX1}fR!AKkA`Ev4S7NR`!<7xLyzJtz!8fRr^j&A{~+4WY>-WJ8Gnx0 z8ICS=QQM;zQv5}79AJyHXk_z|<;iKG5K=TkyW(N!a=id+#y`q>z4mq|zI489AOuV{ zCnwO#2PieGdsQbLRi*tv(h*WP<`M6rtQ9%G*B!qnS$yK#8AII1poO&ByCO-mCG<|2 z?gn+cKasW4Q_s!18@iO}3d7c&o0Wg&P1J((mHFFb=^>;gQ-}2}d?Y&dI?5~J?B4rt zEdm(pQ_;t&%dJ!|NS3Ek>R(Zj9w31BEF1mL5Kx|rE4pUt@ubJF_Etch(a~tpNJyip?>{7rn(XB!mccz=>e3C-jUJj zMzp7Vc;ma_5>5%uJEKP#S>R1xC2 zSEgX|wp%QM!g$1!=)TG)9$vstDOq8j&eZkMvEsMroFC&k9|_YpXz!WFFR&#=N}+>q zc4|d|nN3Y#x=>iplqd&*Gl&+0vYWZFxr$yY%_h*C(Mx^VVEYhmF(9=dCiI{-kksHJ zNFe(vAjpuTi2Hb;U?A5JpfLSoAPMjwof!S{ptoQ?Qb8mj0+JvhE^GjheNYi1NEjYk zu|Sfo2o(^Ra9ApoDs|4jM5U6gDy-=#FCuN?0-|DFh5Drf6-%fJh-~Aqzy7R{>s6Q~b2^seMH{?T&>1d#gi8AI2pm%4~2-e{*T%vX-{OY26 zt8BO)2xYfbFSabQAE?IF2f*; z2`%kRP2=DoYK#(>lu=YO4mjrBC6m$3^N+uqYnRONyqU&<5TjGwG!oa{s%(N2iKjAt zQYRqNWBmI^8^hmk!REZP&?sDK=C@fMf1@eA5UXyJ2KN_F$V|r!W2=7bv-oIA$!HhS zNe}F&ejU85lhDlLSK#{MF2q?x_gFbQ!!%$Ue}K5$-hhY_0AlJ0l1x88iJvwnr*TjU z96Otn9Qg8@-HMtY0b-dH*tI#g+9a@dsBRp z7m$H95US;}Y;K0q){1d?*ktaKFSR_tt8Uc>_OoIVmJ0qcI{nvH)vBpSNXgZ6l4AK< zg>;X$sfCCbrCU%=j{lG2EX(bzBiCL)$4sg4C+ADEIl$!qf?5JS(5u`i6zY_*Vcpw_ zG<_~ve9Zr;7F#hM(8YSd8{(UaGrlH*Y7d^Rw*nO*6x6^KG{!&oFF?ZoAlkq9mwNF3 z$7?tyfve~rFUNmMIf?&M%1H(rHefBNYNH&Hwmn$vE5^qrDHnhL0FRx@mkW;!&6rP>lnbj32^=6g8c%s;SEaR9Es}T)L1o zJCy;Cy2?j@VS6Xo_)O?4$IRtb*j@Oq9@Aj~Zp`wmBh~4Ppy^Y`@@yj|6aQaCOEC#; z|5eCwNd-fy2w;0>Zusxm{G(4)EC^|Lg$4^87mn?j*fp93D0qnq7=9;vZDsmxr?ZnN?D`K^26Onb2PD z5USkr^K9#27h>(&V9#Z=I+ge}F6A?|nWkJKzdVY|L}ffd^U7RAH!VbE{AC5mf6)r0 zpw5y0tN0563@IF_rixK* z|G;|Fn9#J2>?_8r(Ua@{<(i(TFEDNO`YCv6+&bvP_I4){X6zsH16dSbslpB|+1WZ} zx&120ArqSg+ z2+imK{f`TO|NblP!Bv39!Smq0A1-N6_&@cfzf#y5e@NAj2bO22f4QOiD>wLZ->>Pj zk2i2sQURCAnr-6CuY|bY8bdYZzNFHmr4s&n%z*f-Cvs2;kHegh|5N=6!4X~ zOEUm(EdNv&|5805!#DMhBSFbxc`d#WXpdiWu06By7y+Q7CN@TiG)mJz>Pspg0nRRBl^6nk# z#U2<3E7;SobRv#;S4sDd2ma2L`jHd-(I)rEb9dM4auNUsx1BxZ>r3z5PKG^oV0d>Y zPkIiyYNu4bC5YpoZaMx6S05$7BllP}s$GoMOSj9*yHkyCuDtZe-Y$eEkcJ@`;E>H4 zX@ZyVIfnDV;6d!?1Nb>VJ$x)si=RC@e~PMMy04QP@?bQ>$Oq-Rgn$-BM;u3)hj+YV zV^8xtdV979&%fR>Y!_Hp;R-ajw`fMNPqnU+!o^C(ycYpV-c3&RTM6vX)8aOd` zQdqd3z#5<>xm1b(6CfB?Bppy7@I@P=p`^hwpuVZ7#+ZoCLU6WKT>bi!C$!!yU{MB>~E{kKX846as6%tphUxYrt0NuFAh1 zOOTPV%b7>ReY766W58(Di!B^M6%Rsq%^Asth3FwIQ>PfXmqXcVmLz+e0gg+;R2Hu= zb9Q$g2dgst8Z%nKrP66cm1r{ej8gXw$oZIgyC~2eUoHI5FhEPp2`2#^{~6!Zvg%kj zg`Q7%vZjlYoF$5>5ns;R>p4fkeYLO9gL`u8%SMR?Q|S>^Hoss&gPM$JbdQH4)9W+KtJ(9OdXFuOTBgq_`3cWu+B!%`!SMvpC8y!2Y@+yF?Q)F`wSvr zIS~foL#}wK4{`~u`t0+3*B(!`deWr z2;rvvYcf#ho4?mM|48F5@&#Q}uj6zqIc%RlcLkHy;6HUdX9b__^CbtL^;dXS1>2Jt zh!3#zFCz#T5jk^RL--6tc-Yu)qaIqCZ#({W!GX#P3NseJfWknZfb!?H5rH{_Vz6CA z;8D#3*sz#n3ZTYtsd8?6!^F3Ly?`mF51MO4zI)%ZzTi34u6UNSRdqK2K_1`_R!Hnr z#H@9KuXsnA`q3NND_NQzA?5pB<``b_?ttzc3jG~4^&>O#qg<|Dfn&~^R!Gn=Q-CYtD!bFN*iYi|cXj&n92ph$VL^|k2j_k-fSoazPggyLQEr0i{H z$4UlJ9NA0rz2s_~WsW%5V_M`zlgihTO196uEb&je=FIun%e=@=_>Dn^d}-VSo6gjCMoE-AOZ~wXtopLzBNFL3IqUo^1Al zk6#9oIVyimTar@Nh?9~wAy~06t1O}f*E57vahvAv*Q#r7I3eGE|CBrO9 zl=A76E@sH(w2hJJYA@F7f-FdqWyxqh^U}W&(nKo(ql>415K3ohn^`i|S0rB357MV-j6Qu#}9MJGDDfvtFicw+dEtB!5y zH?BR8+fCjzFZCTVv?ajmk;Kg=?}FD6@Y6{#ZF(b$VQnlsG4lJ6$`1$aWILHZoPmVF8pk$tj= zuN)f=Q~s8kbuLZn&_pR~Mf-c;s5?9BN_pomV~EAE_b9WbXT}~Y|3t9B_+Yc|Z_J&j z{sb~-ct`BP=TB`c+^J7_EN!VNVFu_mb4J)i-U*&c8Pee!4srS9~%6b4l zDhE$7V@gES2Y_zi>?+Cy$;~EirCI@o5-|kAmc|dQ&7z6AW&{_RNZ1B9^e>OOl7Ij; zTbOqEjzm~puPRTx>Y{goO$Aw^F%1C{5JieV8XHimVF z7B(+wG?`0cxOMK2e7xxUrW1a?Kcv*JWwB7`R?h zjyub&7a)8~1Aj}9f55ryw7Wd+cJprpUVZ05(|gxQ&3bsd|db*+(hW}(Q#qksKIYU=h02CJ1G=EzS~rZyb`HGn-N`EBvOOEG7*QU zDxnjfw$?QXSDqe)AC)p<-I35ANUIBpr$Mf1@W&dh9YRKbhe33>nm0`fUGb!d^-jM> znd*_KN|)uSaeGLmz%HxI7bx|)Rxju&9sc(v=w%txXTxtU&~CwW<2jOgWemHYI)?p* z8pD2z$FScfM0<{8|M2HX%DsZHL;M^`{2WR6b0i7LPCQ34v?$hRA<)gI@ikJzqKKzP zirXTe8Yymni?yb-$&5RAC<497S9z)E#3ft>NK5wM3f8>N6>%5A6L}XQc_f<%{fWFb z5$aCmrF`@&Kh{$aFV?Vi;*4silzOM`oZR4?ofEai9N@HnQWs(WB-x4ECoWNT@!UQ! z?4Ojtp#AC;>;6eS5C&4{{gWh&aRRT(ryZb<>A$0Y#`NFgG5z-u$Mjxx??obeFH-J2 zucYt2h@F)Qv{(MftJ3(@95lHd^1|T)a~^~|TI{SblFfv+weV+j{UVBAu)}+r9JFARh>XV=Y zBly05cMI3UUc_Wa&4cne%!3N!)1a`^pfezWIEKe8C?)hP=%DskkL}S(?R;%?X}fj` zeX8DDKGJT`!cRoAvg72XhA-$|8f!aNuP_R*hP42qKb>O# z>QW~9N0rO?mfoq$v^o4G`iOX+Wd_x+UuH9Zhrf3j8~vm$=c*q(P)SAA4v-=Z?c)F` ze6YNqL8fxYIYFExbb%AZfcq{^5JU1Lx5}lQ@tGb`FS{TntwW0$-=W3i$w{?; zS!j+PbCMP#OU-SfAfQV+xRwNTV}~{%`2Yqa#zpD}JD8{&{l!fOD8G{zYtf%Wsrvd( zCaM-;dUUukFY9ngtQim;kgh2DVxP8A8 z_IXf8SMa#cxk|W#n>L6@$+AaICMzs|9iqROKF-y}q}($$ZADg$;jAHOe6x*_*p&B~I!u-q>~pkbN@h1vzAYIcEdM z3WSCnAj4Z&hJ2nf$SIVqQY^O0B(}=rtEV9c$nX}Hfvc@V|2TSV%ce3{1AIXx#kOW8 z6Skti+Hg3O5z`uq>4|K<6i#Taw2XF|Plfu3K3d7Ew?i#waAW;6H`Wpo&J1CSF=z4; z3N`X$-NKEvb4L10&*VJPuQMEfd}qC%xQbg5KxduBjr9xsSUY9|w>h{vkao6p!mh=z z=_JXNW^kM!XpmaeHu4;U5HYS0{b%#C4|@(jd%aXGq-cg~h(m-mPYc7=kt!z14&NAHB%7zomb=emQXH!hVfO+XcAI-k z1Ob(-;-z%7GdI@88v|#oVxn*KucDs+dMEv z83j!@pb)U07SN~$FRtc)x|xP{zkpZWGodmxosF+G?`{BQV0><`aV^MTi}f&73WfC$ zOL;c`RtPP#bRjPj8POMxxsXW}^)&yWEE?Ux?WJj$<0d@ zv;V?P3N-B^Zmhewv2I+hY+kv@LhT?oG0>O%SXW)ljrF12SgSLCoypeqs+AX8*Q>M` zCLMsfUiD{|G9K8M>VRHh!ygr_VKfYCYK5Y&fd7=-Duf7cxf_vJ3TL zQcW)tj)d9yz1A_==6Ap>Mjr+5^|D^d%Da?TfuKs|3~oYbyS~OXtRu{OtV=Fsx5wJp zoG1ts?;(b~gEk?&w-|V%=5?_yk3j+AB@@DE#yTgJ%s!BRf#$uA9dC;5V`jE`gL*y& z^=hRW)Qt5^8hNzmdamU}Ke}8?jxNJ#;j9F~?Hh&W@fFOMA&+YMQ(2+PKo70g)+)Zj zcM*@I?DPa9J8k8r4%BrSH`b#r=f%45OTlRSnl@tav6nM3c=gGI-9k3(H2mm=2K;Cy ztkD@19yJbsBTU|SxrRrbBj=dU59P|aA<(3A;iQno7q=c6@z4>vK2JMSlqcuOxrQ@E zd2os-Pd`(X15Y_R2DG_<>zvHEj|qz@oiEDy!@!hYM=-eNmJv+p9s24!ELBaSsNX7X2fx`Iu zQ3-ec7!l)3gRGhr9=8{z#c_M%xV;eptM>Og5x1AY{M$JPo}}-zIUw?KN(-wO`4EDSG%yUKWpEMv3^|c4p1H zdC~BHiT_S8uM@XyU{l&RZQ!K=^dmRcX256bpoJ|I^tH}`f^PK1L7@LVAkZ`h^eHf5 z{36vlKU@K{pHhPu&@%`)u^8A2B4h7=Rf2*GeFzv}iZW-Mtb z|0-P@4ncD6*h$Cyyow25Gj8(^R~y(4FSC&d@PEf`K99m}=8W1fS$jd8T*SeJx2S~D-!4nS+}zM2VB=OAS~el=H+3M1xl(ncoQ7yV`I0lMSp(~;1p z199|e=;HUCp!7MlacE@@5?G;?Uvvoq+83H7{#eTObr^WeaahWu2tMy9zSy`!4v^t3 zECW}3-UwLA8N^l@eDyTs02$uGGH|tj6@X&#!BU>e150@t4=m*!<5_OGgr~SNIE!4J&7i++;i$lpp&SCosVT1B@2nUp}IFwwB>>Dp+&V-V?IKzBJ z@Y+pGWI~^CYv9q`>$tIgmmljRujj`4bAGJbZs5jR7~sabhac;N8@aK6UcryGcoR3) ztNF1mxS1R42l=ty{}yhn-{;4=<5q60vj@4c=7)esMq?WWnT*Cn|NJ=kr3QYP#vS}J zT}~t5m+2Pp%hovfB_r1Ss(#~-g3LBIY-W>SB+_?OL)qHr!4YBwu^Q6%Z+^CFE>Vlzswco-00yi1r7i5qH2O?c}=wu zw^FJUgc~3*Xrezcouq$lx{*E`o-c;~ADQT#@Ef(OAe_Ie72l+P7-;L@R~N)LnPkN` zNf5Fiz6fe-V4d<6nZnkbCPP%C^-dfmnq3`VsB;wmDt=Fxi?e+ z%X-Z6?;uM-$@3iO37VBW=ct$}KT|lIzbN5O_!|L-(_5W^i=u=tbZwGy=XoVexafo( zJ{3Egg5W1np|p^HVr_m;$5okTBx8atxXLsWxJs&r23PUefvZf55?n=37iiH%%SA7^ zg~d7`Ofw}FjlXhm1pF1Z(6y5wOpW8O#PL_c;;$Ss&4KtUGj5AH{>uE@_}VDwY<8*+ zMD|F#K?^_Wedo`Hh(LuyP+3MdE8~AJWyi@&b^ciHnA_2RjMK7)wE%o@TH=T#aYT|h zB1yDjI31DX^+|C=l3167I3fuz)($`6|p5MyJ?&}%3I44DCjIuMF!Ap{74&}%|S z=tJmr=)L`a+r2%lbVUMk`Uk#Dbl%&$+xPeH?%%z=-SeX<1x_sMvl z`^4uy@wrdDz3e{yC>2kN8F6t6jzy`uo|RXy4Ds!rRfHKg5If%m>S@(z67S z)6FmL{7PXuOZIAWX@ewjqB7yL={~0yaLG~W9a!Zf$F~zq!Tp64SPc?BscpTP?U+Gp_c z8N7T3FQ37S?eG={Pxd5U`jx^kYw3fh{i;SHvlj*%(7Bsq<(FKfjn+nyb=w)Gi#kf@ za}fq@>##xFI{3pRa%6k@)9fYK(y$fVSFy=|p9`S*k|()%4W1ZNBJl9|j5K+ruy%#; z2w8~FNaIrZ`jyO^j5OoRvKeXKo>%DU*41dUOG2#--iajy4U@#3d)U^pxf*Ebj}4=hZyXoEOm z#+@j{3E$=-PNO27o;|Wk=Q%V(sC!ntv0!{KCN=Vy(ApeOb)TeM@IRXBIfOKPkVbe#VY+k1W^drgr z69JcH>E2DnEcJF#^=%KAW4$}m@Ge5QQwZ-Wgm)0aT|#(AA-tOq-bo1WE`)a$!cimK z!sMmdSnn!b#9eqyjK}QCW2$*f7mumoF}v}YS{}1IkE!P|Q6AI4Vs!P9MFtmt!ZtkW z6(ee69@V@NkBaiBxjd@lVo*NQZj@_R2zLtMU4`%tLbyu{uLbRPr?tz){LP%dnH!n% zcZE5B3th}#RLEcS-{o&RL(Gc`CT3I+GwLj+Bx!B7r%2M;zuLE-&M)$#z%TL>WT}xe-*F8bPv{LAM@mu2S9E zRSICtb+I|SL;=QBiIYlaU%+o2xh5gBrQB81FC zo_Sbe%skv@$0O2H>~S8ES%+xvndSC8BHy@Qj=!Llqlv<#(0TVMO!7;A!YwI$3KO5g zME;Lcm@L@er!aB5CioO4SkNdGCYEd>ZM9*Nyvyrs2*@NO{{0d^9kN#yHb(Fe}LI2X|)4#y5V&6$V{YxG~$ngzEApJ`PI{gcLHRtp%s@LgX z%0NCj-h@E^q6(BEs!#ua;%WMq3ZbkjeEJt})4yzlL;tcd2K`Gb2K`I2@boYG$NS1+ zYaW=gAT-Qka1p>i+Rl`5iDCA=3k@2RlLjx>cyu_a+e1*-wiyP?S4_?sMtx=CV%&x- z24ZP6f+?_OC{iqq#0$e%qLQ!hphw@020b1R8jq+cb+)$Aed^tRv~|w98@F}pV$4Mr z1FtmX_$Kx&QKy4i*oE`%&RiGZ<^YGhgx4(Q-}8^4^$+9s6l4GhOIO>h)?_u&MOl_w zhz+gLBG-Y*g};YI)O-JtLe@rEcxK^@2l=cHfwhjDW)qh0pzv93i&r)J(4c{46oE>s z^gdu^D4~>0d}TscJ~vdU>^8 zB#jlYnL;QFN7Sp+!jt=Wxc(|iIpHkLqe9*fFL>r{2G>F?P!`({_>>3S zUP?$dc>v3F|I@+U+JHtJMl~(Mf~H||O%2Xo#Q`B8KxT{(@O z)TlL@NtsVi>eT3UP4(pI2dRCrvRM;K(>BXUcCW=kvQrncWUIAg$>I#R(vbG;iw)bQ z%iKFzOa4|(2|!;kiaVOFRco^xP1h#FYOR%{X|nZ0FkC8=1N3pVjM7=raN-M13#Bk< z;Fj@!{6G%Nc*;YrTgH1I!fL1^)G}WEFcvfolNTQLu4VkAO_E6P5e&Bd)j3$&X-FmJ!-IyOv-<(=ZuW;@#FctwoZceW0|?iDBA0$1cpfb>6$g_15_g zT4fobt#kFGSkN>~>X&-AbuNX^BhWrjTIbDw0opoe7_IZ1T&;7)QrBDOMN6?N%Lr|q z=RSr7O~d5n$GqD*$7~3#a|TN5Y>lX;>|J~(?bI~4+A%}X8taxqV^z*5h;F>IP=4|m zs0-zp5C`K5LFS!-RtSvU^-O`~Yb%jH;mm?m$5x_KsuTw9t%|rLk@e5QQaYJ{1}(>b zw-Ji>l(Pz=Z?fzx{(%Q`eKZY|*0Y7WK0#2%&Sw`y8N9BaUl_Qz#?(uanSy9f2R5ti z{wAB%trc1?HW9;-(bv8sqkNuQ%g}g^j8fmpnggRbz5}Cto?E-nsS}vvqGNr>Mfp6p zmZ5!zMfR_Fo$LAziwcupJcmW*^=2i1r0#KTnOy6E=CMq(dEioM8n{3Tr?3=iO+%k# zn7l);frljaRaq@j%d$Nr)iDoAb9nl)e)!daPms%}n|(PY zA?}*#XpJFth2@q)Q%6_ek7a5Oe=H$s3@Bp)^~W->f_idUMUSiL5i%b% zIchOi087UzW6X|K%n!^ z2NLT$-?jRbEVWFYMbYElw)M%q$sZ^N=TO&88^PK&gd)nH!%ra}l{DeIFAu6WWeH94N3^2J*A?Yj&T zXjDPbjniOY(R;anV0R|N-|fNf1o|q9K+6g>9l?YOCuK@F6szhT4Z(14B^(u~I9fGO zl8T~l-m57m&w&WV+3yrkN}$|&tvtd~Q!-r)sgzWs>Ah}j&<49YQANQ+;i}$sUBTAM z{1`az1Z>%O2iSzZ1ArJ&#;Q=gnH*~|PBxXJ>639=aO#DBdU_K-ft%7N<0_PD7L3QV z3$d0c^?N2uTLShDfX#ZfQpK?|>kGg=NC5+2{a*2syG#F+Sqd}eClRnfOCc{>dt7&A77)g?U11zM2 zg{;6rR$!rj3^0Lt)0BNy2h(Qj?MQDbv)*yvn43vZKA@-LiZX4G*6#L&xFPsO3>y@X zrZT&w_8p*)dwvzhJ-^X$&u_WLJuuKX&}pDi2jjLmVM*E3`#Td+VS!tBy}aPH44xetwhIIE<+T$hZjNu{^Wf;xm7egCwMgO_pR3OsnpbWB_ER7Mk-@|4@(dF6PSy#eHQo6XmYT@xc+giqjRyS&9(36=XwZk^ zL3_p!Bu^q2%eLr-Rt;2}saXs1~Kn5)HxL&q-6kDX*_DPP%?akwE z3*3e$2QR>_h9B?F&Er{=Rlm{RJbu5x+B|}qTsMz(FJP&ObmBpOj0auyA{zAec+j3{ zjnFB4i`glRVV%OaXr00s`%d9|*R3*tta`NX6sErDHoSLShUs%S&GwzbycexI1yGag zox(3@Y9dSUY*gP%XwVDrpg+Kaj=YQp?HNM={n4e%5&I+N-4kTM>W?Sm5N{r6oY-ZmdOzEPbWp>4~b4Nn7BO?PD8%z#m>o_rr}V5&L1r1P?M`^~2lP_rq&k?+E4iw)Xw- z4lCV;CkL;@t%h$b%lx1*!M-0JT4~)6gPL6Lhv%WGi7do}ejg8d^H6sbL3&D z(tY>Rz4}%uNJbj57*8W8O@i}X^W|H}ph=L!fb}uI5IZW@tD#!UuDS!W9TCwUB~N5UB;HV zf1qpHqO!N5)!T1Hi?+xO0_K*}95G`pY_H|^MY_D}*$!ZXY(rUpv!&=KfkuMVjyhx@ zWO#>TgT$*07T-r^XCSf2?=vC+IBVNy!?=yujlUl1lt<7=<~F%4=460b6XUdw%Y5kk zd>)FmXnSM7gO=9?btQ9m+=@BQg&#S=w(!N5c1pxWTJyYlwRUq?o;OokuXu!Y*5~H; z5P0Uz@5Zu0P4KpVQG=RDZQ(%;EE!PRI+=FfJ;Bh9i8d=|;fi}sHa*etb}B_O$~+yt z4q-B13%x-J<3KigahY-PBjaKnlemgR=JJc1&ebo5JAfHUA{WnfZoW6oOtr?a&kWDX1es`oGn>gAilTr?OcK(t!ECJ zX_qotmu%X9&Tt<0=$uSW_vq|TC!5)y6efm}hZss8VknMc$nn3}yYl#`iaS1UceB}K z10*0v0=a;Ma2Oy7IXFT>4ib_;!Uhnfz_MAAl}$G8Zh&}#(pnU++Nx-+cvQT>v$oob zRIOU7XuYV`qgv~U;Ehz<@9#JBHZR%T5PSbo_{{Hr{l357Z)SdTyqS6PCi_wh_4i)? z^;i4?nyz<@DVzF_aRXw=t`zHk?8TlRhkN@)eO=H`*NIJvl?^r>si>GTTgywmp9cRm z-KXZI{<}|XSXN963qU)HieCE zGi_*pESq6Wp${+k|FkLUWVH0osH*18QB{xM8C?}MR`K`Xn}7CQ_{ly0d3W{O1C`Zn zy4APOD+PI({o?HK8WMeKXe-swQ+Guz(4pw6p?61B6-HMzpB+s#xz&H--Bj?-yZbM= zv^rI{`qmlge@8&;Uz_*@HGtorP3nET|CN`2jt7}xhsKlXqdZD39n*>Iz(4emczpS{`}BLnHk{1)TcUogJ-js@InckWBPYo+ zCYtmz=7)W8J*rCsUo(cjWZs|A%KnY;CGe=37{Aml`$}Qhm%5|(l?nP6wvW*O{8{WM z&drUg(qB&NpOx8C*`xR!~c2o#Aja^Rdsq))#MZ8gL9Mrw&>B{ zi>l(!qeh#xqN?;$L7_3^+kIO!;utc|_$knS&E+RN`yV%!tG=OsFlxXXZ7cqN(Eq?> z`0CBsfB5#p?UZR2{fjim9wm$EH_4U#T?4R}Ke2E8F3|w?)Orf^zg70_0=)hOonzbk zcO1hbmDb(?q!q<9d=8EgUupVUc=Z}17uQL&hAmbf z<1mk0UUe$2F+%>feY%jpRo|%I$!$h>7~#(dA0zw?ApxzNjF6460HFha;bw&U5PprY zAK_DkQ5XZW5b_Y_BAkV=4PiUNjR_PY)!XFU6L9m+<4JgSBtVIYQ zY(lsI;Yx&^2=|!bBf?V%FC)+>^ch031;4?M;6(T?!VeIxLAVX!=LnA>{2t+TgbxwE zLWo609EVVhup$O|#UQVL803ZUD}>)7e1tH}Dnt=NB|;OzN`$i!F0!Ir2zwCTLa@aO zF&tqmLN$T|VFSWd2oE9bLpXr&HUj=25D|nJgph(T0igh)9AP2CNeFES+Yojm{1V|w zgclKxBBaORH^32E5za^0h434M_YsD~3z3gdJPX8R2~NNbe#V=B=une%@Rkw$S%HxR z-sV@nOuw;W^tA@2QqPNc>z#oMtTNC(wq#r$+FZ5q!=$ zd@hrEF|rq5u+10J=A|$ju9z>4b#cU4WnURJM>(mZ{j}cE@YXYA^H*caUmH{Y#@I4{ zGnxraf>HvSW{6|b3~grC$Td*P{$)d(8M3#i2ss2|G(#qTRwIZt0-F)U89}@e*o{di z7&U{8V6YJkF@i)RNHT(jx&PcMlixyH6yudM#`#rJFIHhW)$0uk~SYiwn=82 zWNEW6vP}xxq)3~Ck(*(((bF+TkZJ^JMv!g<8Agz41Y?b0oDqySf-Gb8WV6fJ(&a;u zi#365CP_yojy+k%{wi|pDaHuLbA;n%gwG?pl*=}` z(&o#^HdEPVYBaYC$Yz?+?de94XLKo_lggJ#2`yq73XBnEaD*8$!q<@tU1*F@#1V>Q zgrkuQRLnNT{kB7iu?#bfIn3hNvt(>@anlo>m5xe?4Wf(j$3G=eH4s5XN6Mo?n}wMMYO22GO_SGI zl<^&Beg|0{pXNUk&oKMxE8ICBkyq(hNdz)~KsJ${jV7g>xe^yd-Lz7|RTAc8!VaIL z%16REW5EX#kj^HhJ*|zdV@>8W+LXYf3z*S8f#PIc!3+fJbiuklmR?=K3F!43?C)eXGFrDV(R_g@K`HL`A+;vzyv+6xi$)6^ASdAil*eAk& z`>g)}6uce*Y$(FvJ`p}-{XtOhdIYec2%q(d@Db||fr8f~fDJ|XqECdwtp6AkydD8; zD8i9G5k6u4r=Z~V2w+1I{@N$PXRQAm6uce*Y$$?B>mA_>)_(~KUXK7a6d|@xgd?o~ z3KYB^0cGGt2};wAL>L;-&O zl3M!q-8;bJ2LsRZ`quP(7f)N3eqDMTZd+_p<%3-(;Kn$8}c5i`JRv)#5vXZft1U4^KeUj%yo_v4 zXTFquTQ%?Q`6=Snx}PmTj@1YAM~L08MdMviI1R7~YvSiTE2*_^p==1}nt zYI~@dmO?3f(?FIdP9WbFG*N5bUPn2e!2VyDP4aVRCswBjS4wfw2(ho6Y-%$}a@`{G z|0hhppGkBJDEdhm#hq70?NX9Yv5L7AzBH=;+siz&t>R8@i|fFDj}R}9NlLPc4csEX zPa(@S6_mmlM}53iBxi4FoFqn6_ndmleIvI*^8|ZMibyG=o-;ay`t!tpN}|W5Q0Y>+7v+Fj#jnjz zVd_pJdI$Fn>pW_O$1{jdMDB&6vGm=tLXlrhG_m~M zvTR{1zo@cM)Ikz2cFd+4yET=({RQ8@C8^Y=v&zYzBlXlqk1+olXo^^c-bmxo4jWO8 z|0jxHH^wD@RfW(;>2XO780&0|Rw`s?boNYG0u5$#gyXq{kI~nx+bqsz^djr_h+T~K z&5cWXS3E5qWOR^q`vu;d0zFbWwW>jUN6SU_iQ+reQ>&I}tF%1L4)hLo2`>?=wHcZT zmb>xs(gxAi3!SXZWb`N_uQpdRBOXR^pbo8)QIL^;Pn)lu12n@z=oGD%bx#UH?<#a2 zTfVQ=F}j*{A8HMZUT5@?wun&)TOQV$7@fqrPc#Rk1lE0~En##D>%P#IG5Va*5p6l6 zyBQtTPGU5c<9)4tM@tf?B@c-=i?h;)f!@jVGNyk^9|`(O)=13Jjl)LACy9M!dre6q zJ%{Ljwe$9x%%Y$^4K}H@<3JDBxk##aW4W#uEKH=6KLIWAZ?sj-gohFn&KEf67)hlN$%u!zt&EY!UU4sG-ozwGS^ZK z*IV8o(v}P+$@jV5OeG}waTQ5^Sw)h6q*Rh@$nWvlJgYq9c{zJNiRo&l^>f*)B%-FF zM4x7UX*|)xtc_#;lSdK#;{u}9EV+m+n^^uG3#ZAFLYBF=1aEu(LyTSW8C+4Eu_+29!HY<_#V6|jwAn+eq$( zM8D&n&LR2goRL)C3X+_{txq=e)b*O7cy3Q10{CAz+j=+*|3UzA03c@fdQnIxZ8 zK=jpxwU7i;Ymq|kta{M;St~$)m(MyGG;Qw5&@N3GP4_|~c{Q?}=$o^N?&3cDQYzJt zrEy$ngxp?2rQVxH{Dq^*@=ycOf-zmx+j(3XHen>C!mTlgAK!mUG<9xm=S?lKZnyrICt9us3FM-4^kGSX4y!cp0ZN zpZnOO+%C0DxAVw6hv}IW$A|jNa@2s{XHEsx`^*-WKgX@y#Pox)L{DV8jeE(Iokld(qQuxv_|U=uWo0-EkJ^)RLYte=^28edKp@TrbDn#c{vOu~OK+if!`Q zWL6!T9&FEZ~2?XVF48q@VLyNO!&f*!Jxotms?0;iy@nTT#j{17=2i&(O8a@@)6a~3Y+O?I*}-v-=U6}E6mr<-h3xI)oWhNqZ!G73cnZ^5?DI(+cMivT$np;8 zG>*HJbKK8y@8BGV*eJDb8<&)Qc5&P)j{6&?D`Sol+70)FH^j0Oz}e%ljh7?TBH@ao^!mKgMw9Sb-~P|?J(9)@fq$3TKASTR?`xMSG`chgXceRHjmoaD3T$yR+AOY|lxsI(he4u! zKo;@Wv4q~%cGp{lRZJO2=nd_Q+Oa_U8C@m{)0g3Y8SeD)65WwG!)_DTjSuCZ{sw-N zxFqA*^f~r;ahtOIMP{YlE{d~yEE7VOH`^B26GWLoH&pDIB|Up{KB3jKCHh-6Au&gy zX4c)H&?H7Vr4pUN=vIZM%qH}xLW${wUQ_7#CPFcDB|38$p~(tOUreY;p%m6_P-rlt zt92BA&-p3zNgSb{D^xl%*FID{tk6{>a_z^7ClopWG(tS1&@X^Si319K0hA)%Qs{Rn ziDHa!mPz#N^k#di2r9HKui2h1&Q<8aMT16Sph07V)yg9)%7~Yqn1i zzgK7?&_waJLbG5wSsYR5$Iu-w63Qj|3^`1H73m5c0Gcie6gsWYicxEKm1?6Ii9qjE zOSAyG0D<9 zQ7DQOasm~L1q$s)P0SSEQK%6mnk_mN>H;biTNHY-aG@v@zgr>EMfE}}6E7)bMSkUf zBDh+jXOKg=I9H)!pbBxNLf0d|DzRIk9Vo+mvEL=p&9Iy=-c)D=P_6h}p{=O-IuX~R zdNNXJ5Mva2v%o4Ai7l-X-3rS^;&O#P2Wk?xDD-2ribMQTq2bUi5&IQ-9Hm_*-c;ys z$YHtoQlYa4S+OTE$|uq9bDQlaiOC9o9Rd1|C{<`W&??cS&>cWd(V|c@kV|Y(XeM%S zi}MuP1YN7RTA?H$kJznH+;O?~b>c~d#sjsBw-lO!68Xdz3R!_p5%HZ8Z2$_0RE3&= zy2LbvPD&Np22rn2dTNV(qqst$*XIfCRPmfbyXQ5SPZOI?QGQOzwVxqwQs{zzc?-o^ zqB+2$lqih%+RqZN1X*YMI&C2=j_XprAjWS;FAX8D{T$J)Q0MSm`*+2y3e83N&K0jK zKM*WL_#G-R0nm;+$eu+3ip>yHcrNZ`obx&g?`jNOzq2UM8pT;+Cs> z%6_A`=jxtXx=B?2M4~0AiJQdz3av&>+#)irk;n_(ZQ}b1jY8YrAr2|D61B8jEZ!l} zy|bI`cZoKIZiMAMV!uL6%U zU9bB5P%HLK%M`LMCbU+6p}DgOZBpn&wtPdORl^7kyCF3H0W~Rf(*!~r6nZR&&^-!0 z%DPcMRre92T?!Qz6M9~uKnbCb6uPjAP~43Y?P4_U#-84@M-(cQ542a*-`LZa9udJC zd-~F2VuwOWK#vQ{PKip;m!1@3cJ}nMC&lcYp}qvvu`|?{fNt1-+0&Ds6o1&+(+Bs7 z4-`5VIqVaMcJ}nTr$ok0pvi6y(0GC)l=G6#5;F|$_HJ_-J$XUHQpWa8feqqA+LeP z+$+a3(!DCa!{{=9F}iq*{Z-LU7jZIn9OSv8kKca}oe)%+Of`v%L`#Fn3_K9P8x z{WbBy{Sy5WW&e}N`Gs09CEsCxOKef7d$!Qt7N0V@1Y>f$_7^eb0f~+z-e-SD)GL&g z|7-gP;<*RZ?1aN@ABo}zrLMKJ_>O_q)*QACl-f zAd|Llk3>)4PPJ&WAC_n`?qaKUn?mnFXVb>)l_(y%cx{_Pug-bfo}j(?m`ZaNy&tgs zMxxtMqCr}JqeA;ey>B0)#s5~_#aMqPX|omDx0uihg?`3pqeA;D2tB3HWsF`?=!phG zdHdA-&Zu6YH>wD&Rp=>3n-sbdo+W9!pHi!mrgAY%+x@&+{Wg4JKTZq2pw>1`pV)Ci z$fn7)4bTX!K2D;aG(8|jYKKxKI*7Y}q_!eWlb$ty9kC~C`|>2(g*FM#Rg|Dhnm5n{&iIR`br0Xj#E0_AITqRH6xUKCx$O#bpw`f-+3dZcxaAcoVgR zdWnjW<`nI=28qruI%3b&4qYx$2jWfFR$L*G7rJ~c@kWXA;Af#WUZDh}Qmk#;DN$?I z5&KMk?a+G?je_MI&GNoPrMTbcYU35UJB^S_p_7ryTy3L5Um*8#E#X6nj>aFcS7?t< zHp$TjX;y2mD6}1SV~sX`ibMg_*#hmQsS<60u3l@NF45c}N9+r=AO1+912tCBqy>*#Hl@pHG9op(EO|nF&-KAQ^Ri@B?D78#mq0ru}n1p58OA6fpbfVV$V-w%E z_L=Q?i?tt!*I@8^rFPua5?z7(R%>tlMCAZK*J$NM zaj!|_Dizv#ZHq#$CJ#&4pna-PW5q(zt&M+Oq8$r9v3G0FDRfe0O2VmH#-B{GHK990 z%lJ?tPx>eJGqsF^5-ou4EG_3Fi82aO5;kcGha{>+U7w@nd@Rv=pewfhyaX1--UUwcTQp_w_*{f5zHw$i$(3EQ-%fb_XzoA!bs_ifq- zQfK>K+Cu0)Rp_F$M4+z~%E($MF3@7E5>3iV1R4w!S_^9bPuvFJ=Un35G!?)Sl8G~cY@OWgms&H z>9#7}#~Pu#dg*?lbZa@@o4s^@?<-v$>yEP-bz^K&_adiR)l1i)bmwrq^}TdwD&0LC zZ)Y#vE~R^g zHfFr9CrM%x(bRO3UsGp)%@#Y`8Fx{ z#QMk6|7W!SnB_koYv3tFt|eXmbQa0GCiF<|X2~X&cn9oHcrM-ncruWbbw1=d?iZam z;lzv1>ypuRl>VKwjPh?|6Q&It4F*cD7$d0(zbYGpU`2>Uupz{MBgBbp{2^Bos8u9` z#*2xdiDEj_5~k%$Yne7N0GU8$zg^DM2|8Sy0-7SaS+bewB_eYH_I^3dcbOgr%@J{0 zc15l@0E#CamOlYnF77mCE+D=xWxn{iXPz5+D6 z!U@_w%PXD{b1J*orW+|tf20&lLo3e|&zNjY=ZH5*}8qnmN1TWf5n7Y2q6q$^3NYC!pWM8^2_8 z!Ghu7f0+4|m}owyOlX7vi@IPy0#6I>{8RU@PtlGPf1;1dKmnP zpp%C>P2JkCxoxJc=I@qzO;4EDIDDpO%!_KeOb5)Lm7ZpLf5W_np4rGNH&E5QQBYNPib8q zQ|=2rkTUv5XVtVfz}UOsbyL|9W%_FX<3(pdbS*$K=e5LAz+E+ z*2Wabznnkae>~A*t0*$xjCPr0uC?q3ZL$n5E;lb%^3xh0fNwA7P;34ud%l@`YcNl@ zOemUTenP8GZZ$hCl%vyfR%1Kl1zB@oQ(SkN*+ae|$Mc7sZ63p3jUlhl`nHKbH9w=> zIeR>Kl8+Z;IfZEf)7fl4o9&aek22meCu{VCd6=mI7P?;& z!EYW~V@WpIM?D~tO&`x&WO>4}vtWsZ?wS>rWb?%hbl3c-N7h-EN-7cL+Z>lz9yVp9T?S7Mre0-< zi%HGcX-SGPr&w`c9G#8x_3#bpo6rxzFP;#iJuLnOg>X9R*f4QgfQ%kvNRMl6OW?`!s9J4|^Qh%SQ z=USzHl^N5*zByx7)J>0R7N=*`gF=gY_Av6*Oec)S9#agBcsIk+AG0}zJlqPpCFYVC z#Kq`$`KSwGwhH8qvFjjeuZiv^zBhjwvpr^3n$>!9%+r}etUr&L+LUbdil;N@5?xRa ze@QkZL6!trays*;GrvU~Og+=Ojp+|Tue1J`wLfO<4J^5hCAYEU9+o`Fk_TDx2uYC3 zHw}rg`&hn@<ww${NecObw9p%a$ zmJ{bRotQQ??tlgNEF^KorI0kF)x^b_e@0HUia1l!XrlYa{M39n=B@fW;xsGO(w*Ao z^1I{W6kpr;%ecd)$40&(w#U4&_>s74k^Yl$H*;$ySqqY%jVm`jI_BlLBcdClgh@Ov z2F07u8bp&oGqC%xY)~fCTwxa{Cgh4?!UZ~7oDDiooDVu#TmhOdUId-Rk_x7Ef8vjz z4wj$9)FnOxT_;RPEg*&rD&v&5imQ;?%}n=*^C8(IE)^>Vz0UmWl81KFAeVNj*a`|c zD8)TTQpleiG|ohP1yh%arBN2qGe21Gu^~=2h-P?iX6@* zhb?nB-{ZM&FfC{5WV)H@wM=JVUGp39j)>RN@i#8FXg}9p)!x%S*1ptYe@z*tO4C-; z4^7va?l!$)I%xXDq?yyr4)b@+PIJJ#)qIutR`Zt_=TEWRYI(%6-?BL7q?jM#KEFL? ze(Wo;Z^Ryr6}B<99NY1>V%uEXM%x*-b8Ne8_t}1F`-AN@TYOw%+?cqfaVN#Cj%$ze z$DI*(cHG5rm&e^0hyE>Mf6&+Q*KX+17Lh>vURdAZuM$NfBtoQ@&Pu=vFue@)#+pjd zh2^!NMVX60U3E)9r?YlxR#{Y@@-ZWrKuyBUc|Ig!A=v|J5>vG}&}o_-lIfr(k*5s; zouLhZq!833inJu~#h@lJQyT_;7N|+g)`o+h18Ty%l#$@eKuw}te@g~G57dM*r6bQj zfLet~OGln7Ky6|@XuN1PrHgY4E-u)OUwFFIe4qJI^Rwnx%;#F(x5UJZikT2|ytUEl zwEC@Etv|BvvOa8m%KEzXL#q~>9y>i&Ag^cBX+ttq+-x%m3x1sp6y?jUm^CELFAvYxn;D+olB96i{<%6&C3y;emizcJGxL7}KM2-?k<$>gN+Mb#31KM0 zFofd}h9itX7>O_nAsHbBVKl-Rgj9qygom~27$iBnv~$&}f9cbvDQ3E2^lP5F=BsOg zy3SD7LUk=t*J5=op{r}vs!C6w)9dW6@Hzv5;%TcQNK2-Z)Dd+0gAR9aNvFe6x(4y{ zBH0$@N0LsTRuD;CI3r>b5v3&&rNxDjvnz_2FiUe?L7$%rFugdEQGP_}jFO1{vvjdL z;Op|c+<|(Zf3pP%lWbmBFzD-Ob_asx9W7NI&NW{5ym^aPRd_wFb-heh)%#jK9S%nX z)soH@XVBg3_nqwQh#K=4@#g!&4UpSnZpR3!h0gUJcQj=~ur-=W=GLzkzC_b6cDMW1 zyUV>^hi`2#YKfNS`JLSct?b63yJ5P1e}ouyf2eD|f4UZ^>kM@*RM#SPEmqf(=@FV% zPg^YP@_MONS5FtURUKXJZofhmP87ovB(~fY^!PeR=JR^pI?&D03xVoAfgmob40*ci ziqWrm>YAS?8ayt)FMxW=UFPWkuI&hd%95$;47&PIGKoXiB6Tg6SKPs3v9rbFla*Z4 z+}x;Ve`&oE!l zut3jHX9`q?1u9~J%CJCXSfDa25LF#6UyFN*-|KL$botz`W4sgL&f1L-BQx4UaQ*B6M|c4w>G(dP8Kn--H7 zAyr@d)+pw>X1?Fk0>r!_Zza-eX@*`)iqWrm>YA^v1?oCOT?^Hbz-R5=%_oC{Tog(~Mlm9x4Q7pk0feWZFVj9#yWVf7l(T-O-twJ^M1 zf0YlIMfB1sM!)8%YreV`sOt=MEmYScbuCuc5?!umP^@R5GsP-{VwFL$%Aia2 zRtXiW42o3-#iG?6T(zXRT36^fmFPL?Oo_^=MCDYXaw<_dm8hIbR8HzzT%vMPS6mu= zEnQxBsc3Kq0;q2^LbIpc?duAb8>_ale?o5}Og~HTQzjC6(Vd#QJT8_}c_|_cpBP^84K#L2tLiO~bOgrP1r`2v3V8 zjyB(hrFn}n;mb&kK7X*c=|cAggY!T}hZ!2JIV~jG%Sz_7+|gXs&|KS4C2Bk^fA0By zUsoq|nD3Bn6O{vfoBfHb;y%rtoq;>(a0Go|^-MT+cOd9)&#hf#Y?~Er8|g*sB`-}+}@>be*l9miH%Fn#eH1PYp!>M zyIrYE4KDVTEpxA-LChV5T(2Cke*@?r4o6tCLnKoTVMEjRjf2M1Wd?s1tyvpr^mbt} zR}&0&!n^*|0oI4LjKk2%oq&d(><+g1S{%nJUdRj`2Q#O?yAv~>F6~nUU8?8Vh^6ob zpa0mIR6EzX;ePV0AgpE%jy?f+BUxynmg~=w7s7@`~0fA}!|w6yp!VL2iX4G{MpWgSt65b)K0A1n+NC*w5weeIpW zW7a!ODZOgl?O*Tq(}RIq*U4PN6?%c9Y4k?yZQa)bBI@`{y{M06QXWZUG;KG?dyDiZ zwpPEh#f=)+*zH)-6TjXW2&w@-q{C!TkH!pB$frIGqrK(&B!Lr(W3Qd!?jC;dPGIDtFze~ zh@=Unsr2mum(TC@tf8@czTer|=5gr-?0NDGuK$1M=#X{mA(xff4Fm7sy$wJd7v8-!%73QP2XiU25<tLK47Dxne7QI1_Jb$?b>6A2i#pxdPH?t}<~BcFdOg7l-1K4<(hDMO61Zi8`pPkE zEh+N|0cT6gD%`o!nTj@NM=OLCzV~IKmQ3S4A7&b$xi>R~=qA=9*1C7u`ZO*RgUB zxV>u~=9V)1zOGUL7rg z3b#KPRY@H>e~RaA7>**TmIU0gIH=?Pnjo6Gy&ttctOcS**0ue5M$1RpuKl}sLa-k_ z=LHKg40V(mUoi50z|Ekm_|dyIprZgIV_#g-;fkJ!uGAySha-t<@Py}88B{nsTy6~N zy%K@5bbC1T-W)!P=pB6^w}RNfQ)`q}7FKZqRUl?{e{=nYjTo($Wj_{r9m*kJWn-9t z5C?JH&=?mps~Y`o>|1ZB+URz5L5JB7wTVTU=Trcitpt`4^Sf}JO;b_nx>c*@IbG}U zbF0-Jw-?f-PH$HPF`8yAO(V3SvDoc$d)C8&&}@X^J3NYRW+)qOcRzB)1QiIgZ$QUY zD;b(LwqYLixVVhE z((hT1rmb^#M^a-d?Cfs#VRG+W<8%63!XMz5e|h}w`CYooFxvJg=KHFB{td*1I`KR| z>d)=h<)POcx~qC;F^IT?A)vqgK+E-wV-y-z2qB4ay6PKOO2Z@T_ezB4foO@yC4RV0 zCe%l(GwN92_i1CMx`H^f$S**MXk_ z4Hpf>RJlBK4O^$;C4hX0m#+#0p5+ziA-}y|?zxrjR=?XF*4Ju$?e0dTC!81z)-!9^ z0p+Z?)Ji7Y8(nU>_LG9X>qg|@#&liVf3e=T&aF1Yum|SUx5@PPMv|wukiG!(%~)r2 zfuXxQh;gd9yVETv40;|QgvZl%B{2@Ac)-$G!)?njYz@Rk!O)4Ok&Kj(F@vDqbr`8l zSJVV>#*pg=Gd0nat`rhs-cSv(z|MyMyTW>x^RgtV^lY`&>?MUsXtmR_fug8(~x| z=|KPS2NXsod~I!)*U&zygh3+9{2pZJ>5%nnxWu zG4pysm{%LK7=k+SB+b1m#Ph;M$Qu%xhGslBW5N$`J5$e~X&Cdm>}hg{e}X**{8nO` zooldG2x5X)%Oc&;zUwKqF0Acnp_N3tr-NiwEgrl_rXh(30|zRS^DXbhu9tj>*K@-~ ze>W{V(7-oq2RLy>jiJvp1CPb8Nd^=}P2*JT=5qPaUmnCS>Ek&G1(vHEzrKTOP=!P^ zSA@i$PnYBCp>q07Y4?jv+ zP3uP*d&1)Ic&#?b!j*2}$r6 z6_5Zoh-B7F=v?nM>=W~XPc-;IJ%T>kTT5qpe+@0PieH zsi6>+ekYzF^=hN7KI;9I9;esWN}aUb*C7Ef5)|7WXf-r08Vu{z24~RKCP3Tz&R5GE zw3&@oqU}LuWn)TUd=HJalG+$#6>lUOZDZtLrHWmRq6+ls#!||g zrRcK~xwt1`2P9m`Y^Z%0^?ohRB3YSwe){>g2Hc!(zrmo##ooz=?bAh8>u=YLuMD_{ z)w?@d!Fu^3Z*N}*xOSpghr!&HW6Cn<~iWTUIYm(O8U zW)MbPyy(jC@lIES-_b^u?4ME))*p3Ml-|(0Z0(YmqvxW&m#1SWA_Q8 zg$|-0*c6eDYKq8*G)14|nc)o)MXn#o4DV62_6chme+(~Z8eOix({(%ji(Ia*P7lUG z?8OCib+nV6kzZ!&$|wguBObHENYNE=%ctK+R;>dulE=qZ4IrtgM*4}SsQP}D$RVl@ z+pMtZ_3pPRWv46L8sl-) zB#fhMe{?J3M%@67=lcd|9`>{z)pCGldj114lB=RHvwoIC{S^d{IURv^Pka65s_8MXXTFsygx>1~z ze|JOBu(>68J6{KMMd5U)Kb4^Nqnxn|nMk(>W`!=(pPjzK&{vY7m&3~f1CPh=vJG^Vth4j`LIBCPJWvze}W+DtpvYT#TyZhvAnB2v|-%f?9hi1@-f2N z+^~%x1;^My9pJVpzo6zS4yk2q5AN4aFbkUTN~nX6HpzYPHjlRjhWzq4@>we0aF7ox zeb0do=oIJxU6;n+VzXC980bE)vNk??3FY-p7h}8*7fP=Ua&oA*e~CiI zC%&lXd7_=;iF$q~;<+8s$;(!5aJ6X{>6m=aU8D;lud^a8tBkKf^n-GEz~foT>F=)h z^{B8bB~Rqh#<0I#%EQlG@&dbqwfshew%Oc%bX>ob>9d>hxwyY)X7xfQOlM4NK0br% z^m(@m!S(2es`N$N27`4^yFpIH=?bFxe~sfZDly`& zi9QXfm1nP>qT3k9Z(XEkjVEnva^SU3gd-_#SDQ1q6xHVoJCtHj^>@ls=r8#h$XAoh z>u&csR>XJxF%KV!z<{h=Mu^;LdhRUuw|2Fw`?>ESB$i>L2a$aKZbm1%{k}eDbJc>e z&qh_)7FD0ksqk&7NE=e>e=VuuOo%+hAO+MjYt}FueiI{a-!eZmvVW*^<;tdX-=2XaN%*`5!!vW6%AR19_e`U_#>>^;a`)Z94coEkbHa;7 z`eu2kQTc3uG*xUsp7a4L|EzE^y45z>wL71>z3d`37^e%um zC9NI408Uv3jH@}-@dI3#W*;8n`B*0e?LB8Y1HHEnaEi}|6=|Or#`@4D?~`z~-uL?I z_4`b^5JI6>f9b8c{xBJ?=m9~GJJ1u|U?xvr;GGfei3HT)IzR5h(2~^?F){tH7oH)z z|4!bO#>O{A@$*ns)iN48F|`*}RkhVt)V{a2SpG&gLpPl%YHck+5Jc=jM0`Lbd_a8g zK}1AEgdmaF5|Qx160s-3@1A$=oAc(qH*??X)cWs#f8M*xIp>~x@44H#=iWEP5Mqr~ zQqwNT-1WiVcf8RCzGKG=r)9jG5-t)Jq1Hc%);r;RUIWV_?V#ubWI7Pg-k9?73Q(xGUK_?BgUu}tyL}T;7^+KL(DvC2*(l^ zZ2;CJs5HN`mkxC*Fj)85sBP0urTQR-is&Zof8vK^(k49!Hf8*9wRV_hRVJ58yl&lw z#smp<=?VSLzLdCW3282t@RCy)#}^i77vLR*Rzi&E7OJY1s|CF+`BNO|nHJgVZ|HKY z9sOHbP92BqSYNv<#()Lirx(W(Fg|ByK{KO^en9+`Z;zM(Z4cuTnxnpxYXqCFvzNgL ze}DE=*aOX*P+y5*#C2+co4TL7V@~$<3cTDh>n`*KFs-^A;tVE&1WP^?4;s9X691{Q zvt?uJKWj9<5;hj_f8sbGkgeh#!=(%15rZ}=^DFi&O5D~laf*Hr_um{?!ow`tkC`?j zUyA&2lzE% z=2?T20Fv1OOR>L*GTn%{jGk1SC@Q!Vf{X;Qfk(|+tcmhm6$E!II!p#PE<+nJ%CCwl zgMy6_8!$9;X>opbhTU?l&Z!kiBx5R7@g3uv?4ZlBVSd4~w29mFXq>dX_4yq;f0&RO zSn8j>K68pe zT&ZWr;X_GXig(q1U}XER%CJj<$`zl(8FWXTuK`Uyte#-qVHu8u&ohU-+oVDh_AZmR zD&tkq923uMt|*xiDPc!6VFNUhyJ!sD)y(SX zARwxKm|G~bfrB(OgTR5h7$T8u1A8KTdg8(DmmMW>@Ww}3=(9`l)^ zDhn|QR;nl(9%dDI;Jpx!(q%MVxIAPSX$;~oH^S~ahOGk=Bs|sOCDl0xf6BU`R}8C* z?EY~rts;w)1(2RQ24D=oh*1++b4cH3TDldgSq@UFO5YEAbfvvDy^I)LROCSdn6`C0 zT%-bn4M4g!euWWjSUNW72z8(ViUgXnw$|XL9(fcns}dU+vo|4HhCoTlvw)d#Gd0I7 zgyn;c?~BIEjr6oKyVcAKe+wp_voHfZB@Rxq`M!~0tLd1MAHvfISy?WsIhzf#yOEVK zHs+`=;a}H0O;et_X#&q48Yhf}cu&zR-UXV1zev*v_s*K48HOw|WpZ2787rSVKKTfB;XdW~c>9g_or+z!{%_}~+cAqBigfkiDx(+~~P5pdajQ}f=anLeWJ4Ucb)opaKz zXWe!G;5DZF+O9a}%A@87PQCpU6YimAz#npd8aVgXo+oNGb$Ke+C9S5Qc2Jf6P$ZssewspIa&Qil!M3pl5Ohm!$s zdbTplhK*hDW11KI@J#`tOz&d#AS1-LL`qWWG|byZ6zcrM;4>P^;QxR$7#zY zmYXdu4SMG_@EeXMOznW;2+Q|Hh?@Z}(l}@YRE&%tMpGggrvT?}vmGv7cf@%(%XwsVK0P~5hLXapT(jkLx(!h z%T(vICmk;|kPdztFc-i#g*fUP z6_6rDauLKO@^Au;s4)(GANQ`}ua=R)8nH;NI@ZoX_dwe!F(kDV0dXnq%_I9HU={#B zg*JE&or2mwMq)=0w+Cu+8h+a593QGGf40mLL>ra?HC~~#O*JLNR%mS-rN!|=&GNSo z+UN`wBb@D1le2v^XB?|BYjd(sH77edmFF=h$ef`-lW-lzJ2_h+=m;f;CYcNr6K0O3|9z$`H(hRpROeH%=5(iQv41uF8uAT!ZDqVe~;mb z*jOT#8B)p#vBgBZLUNoLn3E`S2ImkT8_UH~O2nPxf&0Ql%2T=oIOb}iwJ*hQF9@Dr z3e;kAOijoEhx>2l8u7v*T#_DK%opRBQl{LcGBuY41VTjYR0Co$tq5js(q!Qr?bAZI zMPkfm=h&r=7H)(m!0)S}M;KNMf1Vx~jyF$0?Mb~E@%GAy*Ow6wo!)RaHTutMQ?-|o zv;K^D`((u1HzVGD8S(bdgx3p9+A!2wGSY#Bu6+)MlH`^}`(J98e~9DdE#9)!gi8(H zVO($&gXx0Tuko-1b;Ckx(-~8nPM_Lo-F4+Z?ce(3Wvauyuwaf(TZdV3e{d;32f5## zmt4}$wV_Y8z5Di2xYK|Sm|)PR-6AlG<3WU#4Lo4SV$&T$9!3$r$OCuLlyK}Me8fm6 zPaP)=y@>K7Zjo@fQC7jd0GuhAJdF4wQ!FpXfci3LZnKAn_WA2j~ zbKlIE`(?)5KO-j3zP6aL>a&RAvU+QTHamcP<)djQ25;JL8{6(A?Gj@fs9dNN{v{LN z8>HbX*@Kb%#Hsm`C49vc_F6H8z7`%!4Flsg-8ksw2`hUuhba( zr^eVfH3mwmW9514MH$7ETxvRdrN%JhM^xrdRx^PUrS}|)s{IeDjd_xqVMMTFISsJm zG5XVDpky;)?Uf0uFB8_@nXvjZVeOL%YyS*bJYpZ77OQ~we;D`EMZ8fD4WQB202+HY zfJT1r_hV{0eJ6) zH)7Tv!2Iu!f9kbMtI~3>eKvmQ;+H2{<7S-0dK=K2f=_Ft?54{+=TZ7LZKTufZ^Zh~ zy})y~Y}ie}g){)Oh#d6!YwVuODHZ%?1;ZC&_JVI8yeEMaRaqC(~e;I z69WOb%W6}NPH>Y~P}eOW$%JhCh_ppztZ6^IsijAB)0FF>if)*VlR8Yuw1kM!R*u6o zl%pA3f1m{y6D;n#j5{e0+g9mOstrXp?4h!PpmW{$&^XYyICFD?)Z7{I@%y@^UVwj2 z<83%(_~4$W#Cv&5R}P=led0~yUh5U`chljJ6|ZIV;`biZp(EhKTMV^hp_Nj%Gd zTc8WzV?O-8j=3qpJ!g4^ZvlRt>yp4u;a7lff1E>X`IPXaT$yEjO|asoHb63L8BglE zfazamLf~2>lxO_517EOl-y#&?x&U!wMiLLN-HwKU3F`PA;Zs#5ePNBfNqO2OBrYX{oJb>h?t}PV8i0%A zf8pPoeV1DoZx|dv`@&}^bs^*^8t2Y#7WDTr6JGrAG(W^1DVAUpoQa+QlbVbLt=IIy z@Xga+6W#gSDPGHjEu=P+p&64^t_m|5DDvj;*>oOv8vE0^v>SQ3^XP2l-+{cY!?|M1 zk}`K2oZnrM>aO7TDsj<3WqV=D79ac0e+f4jK=aVA8^gXt!N2R5B9H17Xbk1_66Vyi4c9`TeN_mq2Lzm>) z>C=;%s$V9~oyzfe%CeTbfd!6Xd)C3YjWCXv4t~nWqja64@Efd?;Va0HPpww;gXGMyiHe>OH~?eG;;WoX>DN1^B0ok9)K=eys@4X)(eb`UHGasEJ@gg7T7675bC} z+!q*ZycOh8ZfTze2s_jb<2}J8f2VEg;#1_a8ahR|6V%bir03*teqx9X^HP{bdU=)l zsD*<&z+q^}bqYu*$$SgN@#s;{GCUmXUbw%u}@e@P|18TwZez!t&(p76-RI{>D@<0KdV(e^Ox5$LdPL zk_|>51G(}Bk|0a)^K_AYdcv9KWh7ELp-~ci5_(E%t&|vTBdtrdVTn!AhGmS2Kp?+< ziU+yT3Hl+KoH7OHUTm1d=J5y8oP%WkN+RCBS)0xBLC)N_+H`Q!r}^I@`5(Dk-z1 zbGYAF!|6_HpQgV8+P$F0i_@^LA+-16ZC2<+6&T7{oL@&3!?+Y}bxf z<(wR&(;Us3=6;~e9T0w{>W~J>bccp zN*Tk8Ea|HB&v}MxRf14p;XGJ|%gPTE3jfN{z z*EW`?pgFpx-{=uHP`{)rhK!SrAhngq#nsu;PACCTx;V|0r@^Vqr39|2=L}TYPB3{o zsI4>L@0gI4KBlcK=m={Wv-^|Vm?zuMAP>XUv^K$D6%E~tJK|_~o3Ufm9`aIrtf6J^Je+JUq3^8%MY++%GTsEVA9dL{^r5OG%j_1DxWhvLANG(KRxV(K$ zPto5lX-3zPLRkh^5NfvuM-UTMFwI95Ootn}977uOTrP8|)F2p25$B!OBUkK{5w-`* z!*rnY>8bMPO*#?Hl9ac^j^XJoUoD_E(rQ05u&Be>_?_Y+)M&!*Ue}g@8KXy`|S6`v^Q6zs^7dw_Ssn_6ue^ zP&}8n+fgLkx8(60g?pCM+7my-a+XSXhGTmr7A;gXiqcasx1a?GZ*8dLj%!RCVx@Ci zMN!*He{@n~D2rk`6{n>LMN4H6aTgO6Oi4`x9_7Ji4SP3CUEERkT-Kb*j=@Rn@6V=Pyy6s`UOc)u~GJFH@bWG*?Y^ zs?x}+I(41{yVjd5^)-AWmi1|q=P6_gMx57Te`y)vg{d zQg;bYtUgP^(26>UhRaq>9iKB>%Z+9$5OZf18a~Das<)J7(eNq?7+HzrIICe@xq`MO zf6W}E;pvM8$~FDgOYt0+8_NpXv>0(>Ph{M~33n{5U@WDJ8&5OwZh=$MrBy#ADmI#8 zBJU@;rQ|v$(_~}mo%7d?XW1^vautItw5ix=irK^TQ7>?yyfg-yCb^eZ~ z9A`L>J)BQ_j7w{Ay{H|oilt%K5`hIUAm(KghIz1OO2WK5*XBv^!7`t9*F`{=V{ClY zefTHT;50q8Gu(L8;rjH`;p)s5C`;|2P6}>xPvu^3)~r0za=!H9UuO+mbwZITe~&X$ zCB<&o3RsJm=EyrJo!u|CF;pRWj#}|(!Jf`sN#iw5&-vI!IQ&G=xvWCX=@Q_e`Gjey z>I}60j)wS*8HK1mFWDWp)icf=#07ANx(MeThZAhMhA)^8>+jdFA$BU0=`=eM)RS%# z%QbJ|?rki-wioK}Gjpm&e&JKNe@S~&5^h>_*@SZ3cIL;v2~hNwKi3WZXpS88E1R3& z0SKvgJa#*UE2s6~A7r7O5gN(oXU_zq{z=*6Ijaj0@;rX~nORuFPs{qemYCP z(y>}R*TxKIz>Q9oc&D0$scS^T%_g4eup8Cjbc_qlrMD{M$AJ(~-9V1#XQ@FW;Od`; z=}L77t9HTg=ypn@sL9ymyvG}+D70cGOmv7FJqTJgU#X5=^5nE8SF~+ZiI*pJJh-DA z{m@Ep?NJ~GZn!-x#Wn9x}oV`qh zdUm@RSLXjRyO~X*($+~{M>N#SU}uspx84~w6h%?IxUksczTW7{>8|m6oj*#f4a>WUoRl}a$2D6svp+EO&n>9>>c-n^)2n|vu6CK8Y!^L=f2A>q-tjs10M@J^-b;ubGpQxTBE zu6UT}4Ak2#9unowaNsA9Jg=6{Jbei{E(2X8iWjQeaM_w10Ok_B7vQ(w(e-wakB zqD~cluaoP*e}}*m<-()Js9e1WN;?XKrIbL2YpW(5hNwqp6J4))(Qwg@I+Q8I;>Oh? zbqpy#*Ol|`(U6+L4Z~N_-_cg3Xj;7P+0$4&#at;P1dc%$bQ&7#K{Os=D+)8GH_-fM z4XB;<#71m0gt4kgjpx`chBJ2puSAN7TTG?#x0`MHe|oM{O&I)B%sXux-~81$((VJ1);;&RqGK>}hfAshp~Q1T}){5&~m z9|zEWe^E6sw}W9&971dG25aN<_cLl!*x$9hBD{AF`?p6&Hwsc})RNN>U7_=ZOs8s1 zXh4m&jZ?Y6FWl3Paq(j&MYXd$rNr(}}*A+6rf1{t~1qaK8#IY6u@8GU*mhm1jQ(>5( zcP|9f1h3S{6uDK@Pjg?rpif9Ys_ILew&8nf!1lJ_H~c=GS>xt1psiwJgjed+yjVD$ zD&;OmDRld%Z@8!OmVR~BtXR{%iz_*O6e~iHDHx#R)@nBgdrE#nhm5h>KRH ze+ItueXXI!oB8;j;MLy7@2S6yuk#0UI+ttE6iVhjc^4Y2u{_sRzZ&wnn&uzAaxUE~ zEdKhwLH}ekiwd=Zri`rA$De+O-!3KcBq0GOdG7x%;ILV^DbN!&s67{iIY>D7EEAml zQT)JsM8=Sj&R9gn}0f8aZw!-n`H6M$l9Z`*J&A+#dfDOQuJcx$y4 z=Y8g&9Vb(+wB>C^d04n6_DDMo8t5XISiUOuAiBok7(6-d`d376P^NE-!GT{I&vx*> z#Pu<5LpWU?203*er1e4kEhN3_dUT%JL^u!EpYw_~N++nT^H%38E8Xf0`TmaU0nT07=4DO(otIV#!;89Y7gjGiYh$c(N5OOQ3xT5h zAo8bF=f-a`@bECfgUljaSpQXBbd0Rqy$(ZBRK5kRu@O2wJc5FfG~zw{FKBQIW11@P zB}E0}4KbCd8cdX991C~!v~#!0f0x(mrX~z{LAtCCjDgviI0iJr>w;a3pEn`90OP0R z9U@e0Tx4Q)s4i9I7W^I;rKIBeAXYxc!1&?a`inI130DEP47CDoT~wcn+ho&p4drO5 z6b#vkO+$tN=fNntfg-egeW8>6Y$YFbT(&uGj6Fhz?jqnk_{MqBv`0rve_54_ozb3T zj(T}S6BWQYTPoM*FpafZeQGQNDUKi1rwE@vu|^!7yBbu5XXnXl&AeA1McChsrf{qe zmh`$vPH5rTRYP_(q_ZBaimQ}|W}?_qLeAT)5emBAsy1)EKfEsIP3zRHCno*Wrv@U_ z;w7fvjhfYwABMkEBb&qXf8>p_{8-6B>^NL|@czf8Y~(FR-6TJgLa)d^36)Ztib&H1 zbOGGd%x`BY*BfEN_tjS2WcOco)>B8zwKW)rYb-FjnBt>tmms9b`8){Wm+-9VVEpNs zk}e6R#T@Nyj8xo`&sJy$`Nfour4AJ%7r}Xs+a_G345RheP1w@MdDAv*=@rm&o?PlfgL)w_&oR)l+Fr?ddd}N_wU!yq z6OnK@_`!3rGF2OtzQd}L8M?$<$<^CT!L~SD7_t$IvBlXiKvGQl4$pDCIVhW8-(K->_^5vaR-+cb?E(;s{vFKHMWCf17 z5GhzG)M55S0JTmt=ccBqC%Dof`oTecvm<^;k&Vh{;HFLV&X;#P5yPnUU? zjR~K>R+ObbC4}2@eJHduv7cy5zTYTf%og`Ow?qPBf3D{DuXt+_9}D}d#H|!sq}i; z7RQ<%lUB@{Nn^$qNGMUWQH99V1Yfk-Eup)6%p|)05tJE<}!*puZXKU{f zf6I{C3M^C9aE&44vfu!63E_H~vj;M;=v#us+JWp$z4#48tw1<#PyDPEh}Yt?+FAQ1 zt&(B1p{BLj4ly$yRs49}^^9gUG;JSa7+X!TtNwns4^O*^^d?oDmXMxWpRm^F&*kIS zN7a&5PT#)mb%XJH=)1Y>UrK(queEb2e=u7_^$iju!h{{b%@QEC@*#GUqq4hcWmOJw z;Wm?a(3yFGUp0!lH<83(G$TbL`n@&vG;x>-Cv7g1gNI&=bQWoitBq zWSU-Q-7^lIbvf!xIKvf2w{T zhGqOPUo{U(h6*jcncSflHNk&K$1Y7YmN&0IrjxImBUkeZd%m}5zhdtf;BLWCQ8y*8 z-)+dK>PGAaRJ~E8Thwh>`8!>Xk(~-(mT^M8kq1xr4+d zV`hvK(E{5{L#^TdnKh*Y7XF|>e~1U*_qC<7J~rZ_cgP$-G#G~)q|f}7xL>-A|MswR z*+A&M{R0aAIP9MG&JoPml)Wuv5DAlgkp_4;YP zA%#9x&Uh_Bwl+hy)Vwdq)W86ZMC{oQl1%b07*a}T$4j?XH)Q^pMOAYi0LlVf{s18zcH$ZsHG9^7eJTOu7oMD^JI% zX-KWg`1!w48EV$$Rvm{YSBLWq?x>p8<4$L{JRJr6Q|t_|W`+Iw->9(Al-I4whLWo+ z#RU488kJU;uMnki*9D<;n1A|Qh=1Oc%8pAWYq=fNAN|#trcy{tv- zcrbbr9orxQTKy~Wy}>|eoZw?V7t`Z%QIsmM)2ztNJDA#6@bc^{1dx-VSg$t_WXGJi z9*K<=ytu<%&PNMtP=BnxtD)}pQQV!pPp+OoX6w-suWRlPgf9w{EO7g}2wY6TjHeO2 z2!5OZ#-*~O62#=3@8({u)SEWHwDhz~R^ty`NfFewzExP&_P41D*W0oF2I;){_U%7S zs$=a1b_*n0hx_*bRoxQp=2EYAUtCF5IK_Q2c|+JPc!rci5r5TCS9k@~?T*)pPUX3O zV)579)!ScHMHDKzVjMe|n0fThs*-APwtQp#vt~7QNhz>`*t$3gYLL2kuIuwWHEPM2 zr$#8tz1`effVWlna;MO&v#5-(k}k1oj6qc{OtTYQF9}Eb1#&hUx81_^5 z;p)Uk-K)a4uYU*KS$9^gPB%GCDiwUcx|>Gb{-);*V$H$b*d+VCZ9+H0XlRb*n^=-! zw^!FpC&6^plvB-rXPwgH1#~%S0o|FX(vg*%mkVQ~E@}?Dg6B9!3G4}K(ve~!!PwCw zJbh`VFp|roTyW~E6TA(>rA4LcVNMTk$phJCOk4UD@qb^8U)*WKL53WW+X+j~YuO{Y zwd)Vxf|`GXL~iq;t&*j~>x{KE(}z}DD{k7h_RY%PHZ^WlPH_u$^^M0TNxwPotT#xy zU0CQi-$a>2=eP_!u{?3<%`?R@vGlOpe$-pLd<4#xQ;HioVleyCVVWG%_Vvw>sFd!C zMD)m&D}V8`UYNL}i<*?SsihR96E2e0IKyc$6_Iir2rw>o&*C{J^)oM_7x?*Q--6-G z*`}PY;s{^kQN8>h>Ita`PQzSaH1ffSp5V@Q-Q(;5oC0E|ASWRjh+)5sUFbPDwLM~b zB|7ZfEr0*6Xa4A?cIrOn%U2$`oYu*E-g;{zkAF>Y zJlosXH84xdtM#@lDouPYpvY$#^Xq$9SC?f=ZS-x_zB7# z1b-@PHIo5EQqA7RS2r6TbIVt+OKW*sZ+x|3dF#!=8CY9hzj>Y9bUSD+-Lftr;Fk8L zJZ-#u*E)G*3y-zhn?Pde_I7GotG#{Ww*aY`5b_%@#1Bua7n-TW{TLO3*Oc42gYZT{2HD!}Zo} zUVFXuwrOJiu4`#&_BPpg=`C;L{ePO}?MG~~4qjX5nwvIWdVk}kcli0?#!DX?vAM1j zPlO;-TeH90aIoHbc!Hsp=C#-IMHqQnkJC3f#uM>q1LCws>M*u-^x8kS_)mMwWt$zVuAu<^!_k^qJP2`k7z(k5+%eSa7gS#l&9 zaJmvY(~&l5I?_GTz4xR|)0wU`ZMyeJlg_lHD{am7{dfOP|CV(g1e$UnOLzb7z4zaL z>%af+f4^HPSsx1FkG~-IUc>%h6Dr5kzj^5N;ZP}_%(x@h-xl)o+esi_sNh*cLVA2d zslNnCMf}Kg5*2pS@y%45ZGZH42eyA8L_hZiWA4cDt0Kp*X>F+_!C|Z|jXV`4LIIob z#oS0D-A)>YIFf!+G*m>F`x%fXVnKu6B&KS-|fazcTJVc-Nv5$unWKNDxSGZf^;jI5q#3m zTffd<5!o9;ZlO+Gz`nU%iIiLM>&&?_kVR?Wu-pSGBuLc&1#3BId33D)&@- zj1=I#;)zg9knm~oq}ou7m2U|dPK9dYe+}R^54#2Rq+C3~mVZO4khbfe>F-_SrcqjE zPCuA7F|rgd5MXk&8|5g3f<$tJ78gA&%H#3hhL8V|6_3>TOL?&h1n*OxccWfuSJ};1 z2K^;;GrI-Lt`3Ac{Y`kqO^0fa$*O1%ig1JAQSmc)Pb~4fBV(Zp{S5+)*&(1qW44oF zKZFhHuN9vZ9)HGL8HUsfKmHc(pg#h5c7~AI{fwB&K$+i*4=BjUuJlB17*JU<5DLY- z%!q~Ds1kp1m7%)eRjkk7Dq4({$d)R3S`*Q_5eIY{ZcKdwzb$-}qv>yD5U@RhZMYKxhOXj;!cxw11 zQUCEilg4||$?Pow3Uf)p5`MtO!RQc$!d(^a$1)5;OTiat2!)t~r@OBIF#ASHVv#fk zIw1;EkWcuxwFG@2dI7wGPoQ&iv8F^;@JD}vIDcDNbcJG6hLWYSlq+~eIiMJ-Y(}ke zaULUKF2-PfUzmS4GEvyePdb^Kibw=@ukxIqelr4HD2j|glt8?Qx8X$qY#FR73y&Eu zx{+4q3cUe9VL2Z{_ydUzu-ou2y9@tz2V4*UcC@*`1tadd{n^Ci&P;mqu~BIjWe-wSZD3)bxG%_gQF{L~9ZvY96(()eR%B6&ojTePd4 zTQa}?*!91?^*#5!=f(%#^sM_n`sVwd^-+Kl7lT;ug2-@YaypwFKa`K%`Sw_>x4XBS zFtNj>q3!MJ@9OKqk}WQ1>e{(^(<=5%Oe=}?dl~GdE~wj`m2y%#pI{Zdr2lovzc7xV1K@A zUotn9NX7G0W64a{=CNcxlSM#MKA%jF=Qc^X_j13f(| zpbb!llT zpG~Az#&%B~NF_%vm!?NDho$to1AnVmCk93b27A`@^-JADYnGakO{Me62}!+xbzt&S z2FkH}!zT9s(34(w^FV0#ozG7E=gx};Utg8FdZ?|Z#I-E+#p4$)Ke=`EUyuF8*w$;B zCZGA&r%v`^#h#0g9>MRw;^zza`{Vdsi{C@|`7;MSfu8|X)+$<0ioM&z`+wsk-sKah9KbGgNt?TYno(bNJBLT0PL7!B#H^%tk>RQ$ri@dpn*zQTw<+#sgY5 zB8Rx?E2s<^B_}GAo=T;f+iOQt+0Hatpxk6)R9efy6)b9N7?_&y^R5k(lSmx2>~}$2 zG*ZKvtTYd`?dv&kuy1H!FfrCQ*e~@Bv|R0mD@C}Paa;`Gdpxjne}6JPhW=w?BDWay z)@*_`hw}N!wX0U;Mh{67iCou&W=uyj6RVCU(+7{O>h10xTy-olky)6V<5Qbf6@DepO=ar-~qluKYU=;3)R-xIGp;WW56#&sj z7yNYwB0Hq)xHPsYIe*HknaC!kT(rW?N_=s;*MmRHT)@6MmboE1l1-#@DPl_QYE{&( zJJdP6vx^aT$&7dQTcvd8-ng?{5$ec(_15xb0D!$@ue<$q+s-1LYhYwWRFZcjl4(V3 z&#B&{TlLnv#(HOcR653L!3bP+ASI>87?dFaz-8`<(TfZaGJlg&`q)J3U?w|}$m3~t zeAPrEdw6QH6Cq9_I}RjM$^0}CG!HXSj`BJKB_qjvO6sV?Fo)j~>x>;Cy|`_rqx2rx zGq`%-_ER0DU&3Dl-M62LR=J=}XFgmI4Y}dg8Spa+8QYbPhCS>wIFdkXl4oITtOB5v zFpWsZ^3h5!D}N7+V4yyZ%@z%pz%{2JIGjn3B}wa}l|Fc_3;`r*Qp)D1qvd{fUa~Kd znv$ZG0l0TYEG)%ywXiG*$7eiV7N$poWsFqMNMbx1DQ7>+HjL&mPTrp!%O65><6d?j zU}#hd{8;U}Va9`$4Y3Gwi3e_&Df5B{Nh>P>590UveSdHx+$4AS`~bJ1#bVdOcy0Y< zGo{;dmu5z%kO4j{?LzBR-nB~h+&hC$1@NgK$^KIC+$uxY9@+B^89My`l3hL5&iI1= zmLG7tuD||zxx;_A?CQRDrt1l^=Q!HJ>L64w8^Uk0a zlWB$FWfkE06`~BhQFiwZfb7LHR)Y)i8Aj`8k+3hEiZ+DUv*F=PYHA`aK8|^`x8Qxj zhh%Se*T4z{pq=-04f1oLTs$|Guf}tRo4C;F0)K#x_8>HCY}lU2<+-|ZnZ0d>vjRXy zHhzw%C3f~*JJV4*X-ATr(%e76byPU$EIzek!#rm>52+e|F# zn)MEBm=oXv!rjAg--+MWG;q8ghPO2c^%hV!Wsas1XS3V3l<>Ko;=4X5&;opGohX9M57;PGe@Q!DC&t^dw^SC|G-Es~z3Z_k~ljdM{KL{9tZ- zB0WBp7?+5AF9@xnmtcZCa4o9X?MQkFkzNJ2tEAUeLDg_(;y`9&=9mf+%@sr1k7Nbz zK`HLO9e;dDb`RkXua}E4F^Ngm%`?!oUVrwycm`r^CD1gIIIs$-AOqObgRlsCAO7G9#Z`xC3<~fYnZWm<0E_2Ccy3ZA@j3oS(?HAnxsC-M zlHCK{Tx0MLzqDGsq`wP^e~5?|)GAi%gRmxBTQj*lGFE98U-4#9Rm|(T0VUZ-&3_X{ zbIF@09ELIm8(W7##+LEjBm-KnyX42Ay2Tp(P%D(CNHvtx??OG$*!lAcjey{sz%tuq>mA( z6d-QJ-iH-xRMC^NmrA*6I>!?srHw#Xz!OK6$qiUzDnBXvcsW-S=YP1W?Qr$ahKrY1 zPRpej)us}Y7{DWVl4uid5nT<1ZxN^$&@l|CDqI+2&0(8TE`4EagKDUpWY-y0yZD1# z^sTV69Cg9(98lrX^D5dF+hUG4VuQDsF7z3KmU2-uh8#H_x+FX!2KsfR5z!#c!_X3hIz0x}gK1bCxom+YdLP$94k8RSB1_b8Lx01;eVw`eM33A`x>f@X zf)}b!Uk5WKV2lZ+|603tI1U!z3EX)OFO>{&<^$<7({vDVVn3$UA@YjQ@`wBT4 zYEUjGj?v}P27mDMbYnqB<=v=FOh54tvQ6brw7d}?;Q1VXBY6HG!-}fv@U}EIV}2uc zBoW_54bNitbs~{w zj<`imz}JWqcu_X zT*Zb_HqMR@W70G2^F`^=B{5dkybt-7#GGJ!G>bkCYl*|fJbT!I^WwZ4rt%riEL13C zyNJ<{)_-}{>G&E-K=5$w4w8MPbB$VjLN3|YyC;EB4eyPcd(hmC2(eSSs3X)_(RYvs zRmVXQXFFwZDxsPDET+pQaG*XfVLI_(a(pUFiDOigj#`K*cMw6Aw~>FW1yh{EZ4T#z zXx@0$vC39SFtIXT+do>@Ye^ln75W-e*(^$FYJWN|rKHikG`2gHQ1U)?rhv~@1$eS) z31d-5un2VGQa!|Gy$M54BBI{RB{l76A_2M9xs>clJGj*(PD?w~ZOJCbXx@j0Ng>0M z$Gu#<2Ik3Y&8T*mToFk`{7~j7c~3N{4bWgHl(I*pEGwqkH_W*SmNBH~2Vu$V+*Js0 z&VO14dbxdl_U_%b3Bi@!BA2kAYmKZePWO4v=;nxYp0pU<=QGetgV1WGo0;3VB#mL; z6QQ==BG}mS5T$M9%qk=vzRKZ zpuR&p)RXw9(ADglz&}^!Q@N4R$^GaJOn-IY@~@gon?Hh#Ur2#a5Nfnqu?i3}h9K73 z2#tES^D=fDiFl(Z;$-3MVlvLim8Og~y1N3_xF{YRARqBip6_JOHwU3sM>4Sn*@85; zp|94{tQKlSH}T}OW1_o+081cRz{}$~JE~V%GkQW}bhC-k6M9BBgVN)3Omnv_qkktv zMh{q!tN`d?0Q!Q^X;wT-+253zNKg;4@fNvSIZ+gFb9yv8JxK;j6qVvi*UKnaft?AB zf>{yk1*e!@>0`i$g3#-*dY2{+OZ%k*xny2q-S!r!*FU%eC-KFxFh|YRqSuT5;+5@p zW?@7!^fm6ErN&+*?KZ%0L@J?N34d{(pk)JEp+SgxcBLgWU>Hj06R8wMJFOT}-7UL& zP&$lOM}a&@iIqwSt0O{V7&Vd8W|`17i|Yip%>cK@2zRxC;?YD}N+HOqsQwZ`iwe+0 z1;=mX0EL>BC*)FXmgs2=H;2gERzjUZq=IrwMvW)222C-$LaIybOvRV;41XTiunI?m zf*Dh*Rfw2)P~<$guow|tD~1DRJiOPfk7k@ZdkcgY&0aAysBvVK4$P5;ix~|ogRtC0gH6|D&bbHqW1oDz$seAQ*EMwvr4Ge8+FPRp{CX^u`D55zoeLV-K-9m ziC&b$q4BGw)`A7vm z8|P4<7lwfA&)0^Em46~(^!I$RQo5-}tP1$-1@x>~1ub`S0q>&~H?W)?D@^P#jq$Gl zqk0t`Kv3ARl{%eas1?{@Z6iF0_E;~3Cb4Mv5YAST)Eh|4E>yW8qQGy? zNwcdZ;Wj29l*(L2qc~xR=qf{97hz<7r8cs!@7>@$Now1bV1M!oywWDD+(2Hg?;>!t z+&tEHT3n~9cbXfG8ywEw?Npyih?p%P8xrrbDj>*Ryb89Ecc_p>%D7oX$g8Xh2=Xf4 zTo#bIQS97Fna(BfVs$ro9;p>fDK(G4W&Jq`@hin-(nSzY$1WiR`S+snPwqLomkR)6G3Qc}%jO|SVfRjn7)S-wR= z%6+0W=4{eTTWz1kb%Nig!7m#2m7b72@%SEYu?Eiyi?z^*ZfQS6HH(Fnvolrwi)E^u zg=_l_3WJnA(gthZvDKAAIKpXn8dzPWmtozLiyk&TR+yg3=`6114#J|xF}O9A5Yj54 zDtTnUcz=;9HBc-dx>~g8^suVf4ug}9zzNwMkIzeUoux;wp)6h{w9Yab&j^UM4;HzH zsxYKXcE6T7RNBU}h!H{Zbv53_+VI+k{D_IG##* zZ3u5@F1b)kIz|~Cu^=?*=nzs^@%ZB8UB?)r<-sDeJdnln%(zOU=8W*$G_NY|tm_uUK0@)#F$W&dJLr&EKS<)F36^)of9@PTX zlYbbho*-Q4cpP+27%eilhgA5Zo-*l36ih4Sz41M~GcMpAZ`#7O55I3B}qU1Fa&VacMLw znMi#MSfpE*t%G*)QKpUxpNx;MGdX$N)=*j@Z3wgxx)^95~owyF)+t5+G*WdP~XkuL{P6{5`u!TU2A%uM;ta}d`dP^(}6@^M+CUv1Hf=RuhL7-aS;eTTB zqSkk~xLDueTCwjy56`jh5No^yYISeQ;tCA3W)&HpOMuMT8b{{L&a!CTh^#)>g9bBm zFpEe>a4jend#<-Ep_;7coUrIJ5a=9D`Knas#SEvUM0VHc=+tBq{SPX1j!m1{U|&o~ zHt-g;Ly|Yl5|MKG4e7DX=>+=2jei^WuvsD-?FtFOM&2HF2&O~^(TnJrBhrRcDvm0{ z7&L5ILZFBF``LD&k05Az>kCy=KetOv4_V1B9m-qPn+$JNs|!XH1ZI=^R<(19aVSOe z{G$oqQN4sIK1b;^pGBJ6Ih{t&- zO}EH3_rLA=_kH3;_uu&3-@N)=4}R*ExWECe7GschZVhmarp~}ww0}lZJK)jG&%1Qq ztRv_J??`q^ zy6RMi@1zVSD^z4EJ%7IaXNQga7*K^~?ZYW>8eGC`O(PVS=nc(I=?*R0#y3F4ymrqV z_~<5Ak0K@1W;>HDg>&=cPJ`PTp0fIoQ{L2hgx8AoFgzyC^f=;7?;JSeq0FiWnuMC{ zo!o@Ei3Rhg%{vQJzQ~bNF13^h@1R&gDlze@cNSiWi$0YU7Jq%JDS=R-)4@Aa5ubQb z>qq%a-Ft%Gr$H~F@x2m=7?=i$18Ps z?R@;;CAc2wI{u{#3pz0PXv5Fr@pChNK8~O7;pdO|d02krkB2$#?{Qjg=CrlJA|41Y zgr7c{+2YDTQFoy&0UxJ^n%a5Mp>#R=T;K2KO z@$-B6(RZ*q^*U(xM`PVZ9xSob_eYt`+v;r|8pEM`ndmbJ3rUsLD4soul)Zz zCe`|%?%3wksZ;csnVFH#qT_BYrag_v!w)|!r_*Wq_J7-Nm-G3&{QB3wUVg(H-awx> zzVVIhL%%=#;SbAy`O9Bqr^j!8^BeiCZ+$C0i!kZ)na_Mi{^vjcDbL|h;`!5jAZ^<3 z|NQ4a@)y4F1>(n>-t;ES$^2=ZTa`^)v_<;Pk zzx_=oV}C#V;SV)lJoL~*vV%kE%bex|+lc7<<~P47zxK7Sm4EPqAJ92DQ~DzdC5!U?|=XMMJVI_xYK+vy8iXAf5|U?@qdd+AFS*Hwkdt{bCQqy@4w%4&)@(4 zcav=0ci(-wYrp*EFXh{AyN!7Av!DIUo-nl!dzz2WfBy5-M&J0xH*9Sn@`!Xpv>W)0 zdP;Tt;0Hgbd*-*l{jL1YcfQjK9LdjDzxq{@13R2r|NRUfOg3KjvX@aCi|sAe|Lt#o zJAdiBc%c0-$%F7b>A^ks+#`SKOJB0Q=M3g9bUJM!!g{`kZvKEZqm;W!%(M)Qw<{9|UL z$-e#RPk*xY?c5&P)*pQ)*M0lrM?d)766JV&wqFMjchVvmvRfBoxUm%sh(Z_8)mz_`|kn`H9mKmYk` z?Ph5cKmPGTsCw63cgf%V?stVd?E4UqEe(=UUy+CYstGZHBHcuYBbz&MzOy`u^Q?$@$1NuBh=5u5Ah27b1a@QwI|v^;w|!_kl4BVZqg0A&rg5) zQ~69D4?OUI{IQRHjO3Z;Z^%#aYb4ibv*=!w57HO3|F)mce)hA(*GJ=lKA+khKO`Gh zU3C@9{g5ww`qQ5-Z`rbiK7U{S@|WfRheL>+ssGT{)+UF;VR>w9>=C!?LLP#2_e>m_ zOor-TTU$$dwHOD>8GPzfpK`=c7KgO7w8)1KAC~8PIKg9gpwFQCF#M4XPK)7Ju;-b)2qaKZbaO*R=Y+|NZZmpZnbBs%=2A#6l0WBLoXSEDy!6 z+Q;`;FT#(0$V&d`+SaXG89a)89{>2q%jcbUo|yBadLRsvWyDE7-C)^0^+b@xn8PBIw8n~fVcl1!j)QE#FCuG;q3U3VROhGN6Ix;owU#WzU7dCY7PR zr)z81uB8wDHua71K2^r4TpasT>%U>c2DOa%-O4ac`x zd`dA1ZnjJ1*k{$o{4fVYJgly+CSIW55_7oBcGLB~zCN-O%a<>gmo8mOv877W@bIw8 zTe1G+8-I}RnvGeE17i}xH83zB;-bFhMHgK}Wt

gDA)0fUoKYWr*lT9#X&bf(tH? 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 delta 121651 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