mirror of
https://github.com/proxysu/ProxySU.git
synced 2024-11-22 05:06:08 +03:00
mvvmcross
This commit is contained in:
parent
22e060e14a
commit
a6221c330a
@ -59,4 +59,5 @@ namespace ProxySU_Core.Models.Developers
|
||||
return caddyStr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,4 +131,5 @@ namespace ProxySU_Core.Models.Developers
|
||||
RunCmd("systemctl restart caddy");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,7 +72,7 @@
|
||||
<HintPath>..\packages\ControlzEx.5.0.0\lib\net452\ControlzEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MahApps.Metro, Version=2.0.0.0, Culture=neutral, PublicKeyToken=51482d6f650b2b3f, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MahApps.Metro.2.4.4\lib\net46\MahApps.Metro.dll</HintPath>
|
||||
<HintPath>..\packages\MahApps.Metro.2.4.5\lib\net46\MahApps.Metro.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MaterialDesignColors, Version=2.0.0.2422, Culture=neutral, PublicKeyToken=df2a72020bd7962a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MaterialDesignColors.2.0.0\lib\net452\MaterialDesignColors.dll</HintPath>
|
||||
@ -86,8 +86,8 @@
|
||||
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="QRCoder, Version=1.4.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\QRCoder.1.4.1\lib\net40\QRCoder.dll</HintPath>
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ControlzEx" version="5.0.0" targetFramework="net461" />
|
||||
<package id="MahApps.Metro" version="2.4.4" targetFramework="net461" />
|
||||
<package id="MahApps.Metro" version="2.4.5" targetFramework="net461" />
|
||||
<package id="MaterialDesignColors" version="2.0.0" targetFramework="net461" />
|
||||
<package id="MaterialDesignThemes" version="4.0.0" targetFramework="net461" />
|
||||
<package id="MaterialDesignThemes.MahApps" version="0.1.6" targetFramework="net461" />
|
||||
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.31" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
|
||||
<package id="QRCoder" version="1.4.1" targetFramework="net461" />
|
||||
<package id="SSH.NET" version="2020.0.1" targetFramework="net461" />
|
||||
</packages>
|
86
ProxySuper.Core/Helpers/DateTimeUtils.cs
Normal file
86
ProxySuper.Core/Helpers/DateTimeUtils.cs
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Helpers
|
||||
{
|
||||
public static class DateTimeUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 从国家授时中心获取标准GMT时间,读取https://www.tsa.cn
|
||||
/// GMT时间与UTC时间没有差别,可以UTC=GMT
|
||||
/// </summary>
|
||||
/// <returns>返回网络时间</returns>
|
||||
public static DateTime GetUTCTime()
|
||||
{
|
||||
DateTime time;
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.tsa.cn");
|
||||
request.Method = "HEAD";
|
||||
request.AllowAutoRedirect = false;
|
||||
HttpWebResponse reponse = (HttpWebResponse)request.GetResponse();
|
||||
string cc = reponse.GetResponseHeader("date");
|
||||
reponse.Close();
|
||||
|
||||
bool s = GMTStrParse(cc, out time);
|
||||
return time;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GMTStrParse(string gmtStr, out DateTime gmtTime) //抓取的date是GMT格式的字符串,这里转成datetime
|
||||
{
|
||||
CultureInfo enUS = new CultureInfo("en-US");
|
||||
bool s = DateTime.TryParseExact(gmtStr, "r", enUS, DateTimeStyles.None, out gmtTime);
|
||||
return s;
|
||||
}
|
||||
|
||||
//设置系统时间的API函数
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool SetLocalTime(ref SYSTEMTIME time);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SYSTEMTIME
|
||||
{
|
||||
public short year;
|
||||
public short month;
|
||||
public short dayOfWeek;
|
||||
public short day;
|
||||
public short hour;
|
||||
public short minute;
|
||||
public short second;
|
||||
public short milliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置系统时间
|
||||
/// </summary>
|
||||
/// <param name="dt">需要设置的时间</param>
|
||||
/// <returns>返回系统时间设置状态,true为成功,false为失败</returns>
|
||||
public static bool SetDate(DateTime dt)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
st.year = (short)dt.Year;
|
||||
st.month = (short)dt.Month;
|
||||
st.dayOfWeek = (short)dt.DayOfWeek;
|
||||
st.day = (short)dt.Day;
|
||||
st.hour = (short)dt.Hour;
|
||||
st.minute = (short)dt.Minute;
|
||||
st.second = (short)dt.Second;
|
||||
st.milliseconds = (short)dt.Millisecond;
|
||||
bool rt = SetLocalTime(ref st);
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
}
|
26
ProxySuper.Core/Models/IProjectSettings.cs
Normal file
26
ProxySuper.Core/Models/IProjectSettings.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public interface IProjectSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域名
|
||||
/// </summary>
|
||||
string Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 额外需要开放的端口
|
||||
/// </summary>
|
||||
List<int> FreePorts { get; }
|
||||
}
|
||||
}
|
39
ProxySuper.Core/Models/TrojanGoSettings.cs
Normal file
39
ProxySuper.Core/Models/TrojanGoSettings.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public class TrojanGoSettings : IProjectSettings
|
||||
{
|
||||
public List<int> FreePorts
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 域名
|
||||
/// </summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string MaskDomain { get; set; }
|
||||
}
|
||||
}
|
69
ProxySuper.Core/Models/XraySettings.cs
Normal file
69
ProxySuper.Core/Models/XraySettings.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public partial class XraySettings : IProjectSettings
|
||||
{
|
||||
public List<int> FreePorts
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<int>
|
||||
{
|
||||
VLESS_KCP_Port,
|
||||
VMESS_KCP_Port,
|
||||
ShadowsocksPort,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UUID
|
||||
/// </summary>
|
||||
public string UUID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域名
|
||||
/// </summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string MaskDomain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 安装类型
|
||||
/// </summary>
|
||||
public List<XrayType> Types { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据xray类型获取路径
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public string GetPath(XrayType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case XrayType.VLESS_WS:
|
||||
return VLESS_WS_Path;
|
||||
case XrayType.VMESS_TCP:
|
||||
return VMESS_TCP_Path;
|
||||
case XrayType.VMESS_WS:
|
||||
return VMESS_WS_Path;
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
ProxySuper.Core/Models/XraySettings_SS.cs
Normal file
26
ProxySuper.Core/Models/XraySettings_SS.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public partial class XraySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// ss password
|
||||
/// </summary>
|
||||
public string ShadowsocksPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ss method
|
||||
/// </summary>
|
||||
public string ShadowsocksMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ss port
|
||||
/// </summary>
|
||||
public int ShadowsocksPort { get; set; }
|
||||
}
|
||||
}
|
13
ProxySuper.Core/Models/XraySettings_Trojan.cs
Normal file
13
ProxySuper.Core/Models/XraySettings_Trojan.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public partial class XraySettings
|
||||
{
|
||||
public string TrojanPassword { get; set; }
|
||||
}
|
||||
}
|
41
ProxySuper.Core/Models/XraySettings_VLESS.cs
Normal file
41
ProxySuper.Core/Models/XraySettings_VLESS.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public partial class XraySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// websocket path
|
||||
/// </summary>
|
||||
public string VLESS_WS_Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// kcp seed
|
||||
/// </summary>
|
||||
public string VLESS_KCP_Seed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// kcp type
|
||||
/// </summary>
|
||||
public string VLESS_KCP_Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// kcp port
|
||||
/// </summary>
|
||||
public int VLESS_KCP_Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// grpc port
|
||||
/// </summary>
|
||||
public string VLESS_gRPC_Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// grpc service name
|
||||
/// </summary>
|
||||
public string VLESS_gRPC_ServiceName { get; set; }
|
||||
}
|
||||
}
|
36
ProxySuper.Core/Models/XraySettings_VMESS.cs
Normal file
36
ProxySuper.Core/Models/XraySettings_VMESS.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public partial class XraySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// vmess websocket path
|
||||
/// </summary>
|
||||
public string VMESS_WS_Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// mvess tcp path
|
||||
/// </summary>
|
||||
public string VMESS_TCP_Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// vmess kcp seed
|
||||
/// </summary>
|
||||
public string VMESS_KCP_Seed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// vmess kcp type
|
||||
/// </summary>
|
||||
public string VMESS_KCP_Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// vmess kcp port
|
||||
/// </summary>
|
||||
public int VMESS_KCP_Port { get; set; }
|
||||
}
|
||||
}
|
34
ProxySuper.Core/Models/XrayType.cs
Normal file
34
ProxySuper.Core/Models/XrayType.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Models
|
||||
{
|
||||
public enum XrayType
|
||||
{
|
||||
// 入口
|
||||
VLESS_TCP_XTLS = 100,
|
||||
|
||||
// VLESS 101开头
|
||||
VLESS_TCP = 101,
|
||||
VLESS_WS = 102,
|
||||
VLESS_H2 = 103,
|
||||
VLESS_KCP = 104,
|
||||
VLESS_gRPC = 110,
|
||||
|
||||
// VMESS 201开头
|
||||
VMESS_TCP = 201,
|
||||
VMESS_WS = 202,
|
||||
VMESS_H2 = 203,
|
||||
VMESS_KCP = 204,
|
||||
|
||||
// Trojan 301开头
|
||||
Trojan_TCP = 301,
|
||||
Trojan_WS = 302,
|
||||
|
||||
// SS
|
||||
ShadowsocksAEAD = 401
|
||||
}
|
||||
}
|
@ -34,6 +34,14 @@
|
||||
<Reference Include="MvvmCross, Version=7.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MvvmCross.7.1.2\lib\net461\MvvmCross.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\json.net\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="Renci.SshNet, Version=2020.0.1.0, Culture=neutral, PublicKeyToken=1cee9f8bde3db106, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SSH.NET.2020.0.1\lib\net40\Renci.SshNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Console, Version=4.0.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Console.4.3.1\lib\net46\System.Console.dll</HintPath>
|
||||
@ -48,7 +56,21 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.cs" />
|
||||
<Compile Include="Helpers\DateTimeUtils.cs" />
|
||||
<Compile Include="Models\IProjectSettings.cs" />
|
||||
<Compile Include="Models\TrojanGoSettings.cs" />
|
||||
<Compile Include="Models\XraySettings_SS.cs" />
|
||||
<Compile Include="Models\XraySettings_Trojan.cs" />
|
||||
<Compile Include="Models\XraySettings_VLESS.cs" />
|
||||
<Compile Include="Models\XraySettings.cs" />
|
||||
<Compile Include="Models\XraySettings_VMESS.cs" />
|
||||
<Compile Include="Models\XrayType.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\ProjectBase.cs" />
|
||||
<Compile Include="Services\TrojanGoConfigBuilder.cs" />
|
||||
<Compile Include="Services\TrojanGoProject.cs" />
|
||||
<Compile Include="Services\XrayConfigBuilder.cs" />
|
||||
<Compile Include="Services\XrayProject.cs" />
|
||||
<Compile Include="ViewModels\SecondViewModel.cs" />
|
||||
<Compile Include="ViewModels\MainViewModel.cs" />
|
||||
</ItemGroup>
|
||||
|
746
ProxySuper.Core/Services/ProjectBase.cs
Normal file
746
ProxySuper.Core/Services/ProjectBase.cs
Normal file
@ -0,0 +1,746 @@
|
||||
using ProxySuper.Core.Helpers;
|
||||
using ProxySuper.Core.Models;
|
||||
using Renci.SshNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace ProxySuper.Core.Services
|
||||
{
|
||||
public enum CmdType
|
||||
{
|
||||
None,
|
||||
Apt,
|
||||
Dnf,
|
||||
Yum
|
||||
}
|
||||
|
||||
public abstract class ProjectBase<TSettings> where TSettings : IProjectSettings
|
||||
{
|
||||
private SshClient _sshClient;
|
||||
|
||||
protected Action<string> WriteOutput;
|
||||
|
||||
protected CmdType CmdType { get; set; }
|
||||
|
||||
protected bool IsSELinux { get; set; }
|
||||
|
||||
protected bool OnlyIpv6 { get; set; }
|
||||
|
||||
protected string IPv4 { get; set; }
|
||||
|
||||
protected string IPv6 { get; set; }
|
||||
|
||||
protected TSettings Parameters { get; set; }
|
||||
|
||||
public ProjectBase(SshClient sshClient, TSettings parameters, Action<string> writeOutput)
|
||||
{
|
||||
_sshClient = sshClient;
|
||||
WriteOutput = writeOutput;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
protected string RunCmd(string cmdStr)
|
||||
{
|
||||
var cmd = _sshClient.CreateCommand(cmdStr);
|
||||
WriteOutput(cmdStr);
|
||||
|
||||
var result = cmd.Execute();
|
||||
WriteOutput(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行安装命令
|
||||
/// </summary>
|
||||
public abstract void Install();
|
||||
|
||||
/// <summary>
|
||||
/// 配置系统基础环境
|
||||
/// </summary>
|
||||
protected void EnsureSystemEnv()
|
||||
{
|
||||
string cmd;
|
||||
|
||||
// 确认安装命令
|
||||
if (CmdType == CmdType.None)
|
||||
{
|
||||
cmd = RunCmd("command -v apt-get");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
CmdType = CmdType.Apt;
|
||||
}
|
||||
}
|
||||
|
||||
if (CmdType == CmdType.None)
|
||||
{
|
||||
cmd = RunCmd("command -v dnf");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
CmdType = CmdType.Dnf;
|
||||
}
|
||||
}
|
||||
|
||||
if (CmdType == CmdType.None)
|
||||
{
|
||||
cmd = RunCmd("command -v yum");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
CmdType = CmdType.Yum;
|
||||
}
|
||||
}
|
||||
|
||||
// systemctl
|
||||
cmd = RunCmd("command -v systemctl");
|
||||
var hasSystemCtl = !string.IsNullOrEmpty(cmd);
|
||||
|
||||
// SELinux
|
||||
cmd = RunCmd("command -v getenforce");
|
||||
IsSELinux = !string.IsNullOrEmpty(cmd);
|
||||
|
||||
if (CmdType == CmdType.None || !hasSystemCtl)
|
||||
{
|
||||
throw new Exception("系统缺乏必要的安装组件如:apt-get||dnf||yum||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本");
|
||||
}
|
||||
|
||||
|
||||
// 判断是否启用了SELinux,如果启用了,并且工作在Enforcing模式下,则改为Permissive模式
|
||||
if (IsSELinux)
|
||||
{
|
||||
cmd = RunCmd("getenforce");
|
||||
|
||||
// 检测到系统启用SELinux,且工作在严格模式下,需改为宽松模式
|
||||
if (cmd.Contains("Enforcing"))
|
||||
{
|
||||
RunCmd("setenforce 0");
|
||||
RunCmd(@"sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保Root账户登陆
|
||||
/// </summary>
|
||||
protected void EnsureRootAuth()
|
||||
{
|
||||
// 禁止一些可能产生的干扰信息
|
||||
RunCmd(@"sed -i 's/echo/#echo/g' ~/.bashrc");
|
||||
RunCmd(@"sed -i 's/echo/#echo/g' ~/.profile");
|
||||
|
||||
|
||||
// 检测是否运行在Root权限下
|
||||
var cmd = RunCmd("id -u");
|
||||
if (!cmd.Equals("0\n"))
|
||||
{
|
||||
throw new Exception("请使用Root账户登陆主机");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置IPV6环境
|
||||
/// </summary>
|
||||
protected void ConfigureIPv6()
|
||||
{
|
||||
if (IsOnlyIpv6())
|
||||
{
|
||||
SetNat64();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置必要的软件
|
||||
/// </summary>
|
||||
protected void ConfigureSoftware()
|
||||
{
|
||||
string cmd = RunCmd("command -v sudo");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
RunCmd(GetInstallCmd("sudo"));
|
||||
}
|
||||
|
||||
// 安装curl,wget,unzip
|
||||
cmd = RunCmd("command -v curl");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
RunCmd(GetInstallCmd("curl"));
|
||||
}
|
||||
|
||||
cmd = RunCmd("command -v wget");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
RunCmd(GetInstallCmd("wget"));
|
||||
}
|
||||
|
||||
cmd = RunCmd("command -v unzip");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
RunCmd(GetInstallCmd("unzip"));
|
||||
}
|
||||
|
||||
// 安装dig
|
||||
cmd = RunCmd("command -v dig");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
if (CmdType == CmdType.Apt)
|
||||
{
|
||||
RunCmd(GetUpdateCmd());
|
||||
RunCmd(GetInstallCmd("dnsutils"));
|
||||
}
|
||||
else if (CmdType == CmdType.Dnf)
|
||||
{
|
||||
RunCmd(GetUpdateCmd());
|
||||
RunCmd(GetInstallCmd("bind-utils"));
|
||||
}
|
||||
else if (CmdType == CmdType.Yum)
|
||||
{
|
||||
RunCmd(GetUpdateCmd());
|
||||
RunCmd(GetInstallCmd("bind-utils"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理极其少见的xz-utils未安装的情况
|
||||
if (CmdType == CmdType.Apt)
|
||||
{
|
||||
RunCmd(GetInstallCmd("xz-utils"));
|
||||
}
|
||||
else
|
||||
{
|
||||
RunCmd(GetInstallCmd("xz-devel"));
|
||||
}
|
||||
|
||||
// 检测是否安装lsof
|
||||
cmd = RunCmd("command -v lsof");
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
RunCmd(GetInstallCmd("lsof"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭端口
|
||||
/// </summary>
|
||||
/// <param name="portList"></param>
|
||||
protected void ClosePort(params int[] portList)
|
||||
{
|
||||
string cmd;
|
||||
|
||||
cmd = RunCmd("command -v firewall-cmd");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
//有很奇怪的vps主机,在firewalld未运行时,端口是关闭的,无法访问。所以要先启动firewalld
|
||||
//用于保证acme.sh申请证书成功
|
||||
cmd = RunCmd("firewall-cmd --state");
|
||||
if (cmd.Trim() != "running")
|
||||
{
|
||||
RunCmd("systemctl restart firewalld");
|
||||
}
|
||||
|
||||
foreach (var port in portList)
|
||||
{
|
||||
RunCmd($"firewall-cmd --zone=public --remove-port={port}/tcp --permanent");
|
||||
RunCmd($"firewall-cmd --zone=public --remove-port={port}/udp --permanent");
|
||||
}
|
||||
RunCmd("yes | firewall-cmd --reload");
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = RunCmd("command -v ufw");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
foreach (var port in portList)
|
||||
{
|
||||
RunCmd($"ufw delete allow {port}/tcp");
|
||||
RunCmd($"ufw delete allow {port}/udp");
|
||||
}
|
||||
RunCmd("yes | ufw reload");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开放端口
|
||||
/// </summary>
|
||||
/// <param name="portList"></param>
|
||||
protected void OpenPort(params int[] portList)
|
||||
{
|
||||
|
||||
string cmd;
|
||||
|
||||
cmd = RunCmd("command -v firewall-cmd");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
//有很奇怪的vps主机,在firewalld未运行时,端口是关闭的,无法访问。所以要先启动firewalld
|
||||
//用于保证acme.sh申请证书成功
|
||||
cmd = RunCmd("firewall-cmd --state");
|
||||
if (cmd.Trim() != "running")
|
||||
{
|
||||
RunCmd("systemctl restart firewalld");
|
||||
}
|
||||
|
||||
foreach (var port in portList)
|
||||
{
|
||||
RunCmd($"firewall-cmd --zone=public --add-port={port}/tcp --permanent");
|
||||
RunCmd($"firewall-cmd --zone=public --add-port={port}/udp --permanent");
|
||||
}
|
||||
RunCmd("yes | firewall-cmd --reload");
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = RunCmd("command -v ufw");
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
foreach (var port in portList)
|
||||
{
|
||||
RunCmd($"ufw allow {port}/tcp");
|
||||
RunCmd($"ufw allow {port}/udp");
|
||||
}
|
||||
RunCmd("yes | ufw reload");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置防火墙
|
||||
/// </summary>
|
||||
protected void ConfigureFirewall()
|
||||
{
|
||||
var portList = new List<int>();
|
||||
portList.Add(80);
|
||||
portList.Add(Parameters.Port);
|
||||
portList.AddRange(Parameters.FreePorts);
|
||||
|
||||
OpenPort(portList.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置同步时间差
|
||||
/// </summary>
|
||||
protected void SyncTimeDiff()
|
||||
{
|
||||
RunCmd("rm -f /etc/localtime");
|
||||
RunCmd("ln -s /usr/share/zoneinfo/UTC /etc/localtime");
|
||||
|
||||
var result = RunCmd("date +%s");
|
||||
var vpsSeconds = Convert.ToInt64(result);
|
||||
var localSeconds = (int)(DateTime.Now.ToUniversalTime() - DateTime.Parse("1970-01-01")).TotalSeconds;
|
||||
|
||||
if (Math.Abs(vpsSeconds - localSeconds) >= 90)
|
||||
{
|
||||
// 同步本地时间
|
||||
var netUtcTime = DateTimeUtils.GetUTCTime();
|
||||
DateTimeUtils.SetDate(netUtcTime.ToLocalTime());
|
||||
|
||||
// 同步VPS时间
|
||||
var utcTS = DateTimeUtils.GetUTCTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
long timeStampVPS = Convert.ToInt64(utcTS.TotalSeconds);
|
||||
RunCmd($"date --set=\"$(date \"+%Y-%m-%d %H:%M:%S\" -d @{timeStampVPS.ToString()})\"");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证域名是否绑定了主机
|
||||
/// </summary>
|
||||
protected void ValidateDomain()
|
||||
{
|
||||
if (OnlyIpv6)
|
||||
{
|
||||
string cmdFilter = @"| grep -oE '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))' | head -n 1";
|
||||
var cmd = $"dig @resolver1.opendns.com AAAA {Parameters.Domain} +short -6 {cmdFilter}";
|
||||
var result = RunCmd(cmd).TrimEnd('\r', '\n');
|
||||
|
||||
if (result == IPv6) return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
string cmdFilter = @"| grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1";
|
||||
var cmd = $"dig @resolver1.opendns.com A {Parameters.Domain} +short -4 {cmdFilter}";
|
||||
var result = RunCmd(cmd).TrimEnd('\r', '\n');
|
||||
|
||||
if (result == IPv4) return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
var btnResult = MessageBox.Show(
|
||||
$"{Parameters.Domain}未能正常解析到服务器的IP,如果您使用了CDN请忽略,是否继续安装?", "提示", MessageBoxButton.YesNo);
|
||||
|
||||
if (btnResult == MessageBoxResult.No)
|
||||
{
|
||||
throw new Exception($"域名解析失败,安装停止!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否安装某个软件
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
protected bool FileExists(string path)
|
||||
{
|
||||
var cmdStr = $"if [[ -f {path} ]];then echo '1';else echo '0'; fi";
|
||||
var cmd = RunCmd(cmdStr);
|
||||
return cmd.Trim() == "1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装 Caddy
|
||||
/// </summary>
|
||||
protected void InstallCaddy()
|
||||
{
|
||||
RunCmd("rm -rf caddy_install.sh");
|
||||
RunCmd("curl -o caddy_install.sh https://raw.githubusercontent.com/proxysu/shellscript/master/Caddy-Naive/caddy-naive-install.sh");
|
||||
RunCmd("yes | bash caddy_install.sh");
|
||||
RunCmd("rm -rf caddy_install.sh");
|
||||
RunCmd("systemctl enable caddy.service");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载 Caddy
|
||||
/// </summary>
|
||||
protected void UninstallCaddy()
|
||||
{
|
||||
RunCmd("rm -rf caddy_install.sh");
|
||||
RunCmd("curl -o caddy_install.sh https://raw.githubusercontent.com/proxysu/shellscript/master/Caddy-Naive/caddy-naive-install.sh");
|
||||
RunCmd("yes | bash caddy_install.sh uninstall");
|
||||
RunCmd("rm -rf caddy_install.sh");
|
||||
RunCmd("rm -rf /usr/share/caddy");
|
||||
}
|
||||
|
||||
|
||||
#region 检测系统环境
|
||||
|
||||
private bool IsOnlyIpv6()
|
||||
{
|
||||
string cmd;
|
||||
|
||||
cmd = RunCmd(@"curl -s https://api.ip.sb/ip --ipv4 --max-time 8");
|
||||
IPv4 = cmd.TrimEnd('\r', '\n');
|
||||
|
||||
if (!string.IsNullOrEmpty(IPv4))
|
||||
{
|
||||
OnlyIpv6 = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd = RunCmd(@"curl -s https://api.ip.sb/ip --ipv6 --max-time 8");
|
||||
IPv6 = cmd.TrimEnd('\r', '\n');
|
||||
|
||||
if (string.IsNullOrEmpty(IPv6))
|
||||
{
|
||||
throw new Exception("未检测可用的的IP地址");
|
||||
}
|
||||
|
||||
OnlyIpv6 = true;
|
||||
return OnlyIpv6;
|
||||
}
|
||||
|
||||
private bool SetPortFree(int port, bool force = true)
|
||||
{
|
||||
string result = RunCmd($"lsof -n -P -i :{port} | grep LISTEN");
|
||||
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
var btnResult = MessageBox.Show($"{port}端口被占用,将强制停止占用{port}端口的程序?", "提示", MessageBoxButton.YesNo);
|
||||
if (btnResult == MessageBoxResult.No)
|
||||
{
|
||||
throw new Exception($"{port}端口被占用,安装停止!");
|
||||
}
|
||||
|
||||
string[] process = result.Split(' ');
|
||||
RunCmd($"systemctl stop {process[0]}");
|
||||
RunCmd($"systemctl disable {process[0]}");
|
||||
RunCmd($"pkill {process[0]}");
|
||||
return SetPortFree(port, force: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ConfigurePort()
|
||||
{
|
||||
if (Parameters.Port == 80 || Parameters.Port == 443)
|
||||
{
|
||||
SetPortFree(80);
|
||||
SetPortFree(443);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPortFree(80);
|
||||
SetPortFree(443);
|
||||
SetPortFree(Parameters.Port);
|
||||
|
||||
Parameters.FreePorts.ForEach(port =>
|
||||
{
|
||||
SetPortFree(port);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetNat64()
|
||||
{
|
||||
var dns64List = FilterFastestIP();
|
||||
if (dns64List.Count == 0)
|
||||
{
|
||||
throw new Exception("未找到有效的Nat64网关");
|
||||
}
|
||||
|
||||
var exists = FileExists("/etc/resolv.conf.proxysu");
|
||||
if (!exists)
|
||||
{
|
||||
var cmdStr = @"mv /etc/resolv.conf /etc/resolv.conf.proxysu";
|
||||
RunCmd(cmdStr);
|
||||
}
|
||||
|
||||
foreach (var gateip in dns64List)
|
||||
{
|
||||
RunCmd($"echo \"nameserver {gateip}\" > /etc/resolv.conf");
|
||||
}
|
||||
}
|
||||
|
||||
protected void RemoveNat64()
|
||||
{
|
||||
RunCmd("rm /etc/resolv.conf");
|
||||
RunCmd("mv /etc/resolv.conf.proxysu /etc/resolv.conf");
|
||||
}
|
||||
|
||||
private List<string> FilterFastestIP()
|
||||
{
|
||||
string[] gateNat64 = {
|
||||
"2a01:4f9:c010:3f02::1",
|
||||
"2001:67c:2b0::4",
|
||||
"2001:67c:2b0::6",
|
||||
"2a09:11c0:f1:bbf0::70",
|
||||
"2a01:4f8:c2c:123f::1",
|
||||
"2001:67c:27e4:15::6411",
|
||||
"2001:67c:27e4::64",
|
||||
"2001:67c:27e4:15::64",
|
||||
"2001:67c:27e4::60",
|
||||
"2a00:1098:2b::1",
|
||||
"2a03:7900:2:0:31:3:104:161",
|
||||
"2a00:1098:2c::1",
|
||||
"2a09:11c0:100::53",
|
||||
};
|
||||
|
||||
Dictionary<string, float> dns64List = new Dictionary<string, float>();
|
||||
foreach (var gateip in gateNat64)
|
||||
{
|
||||
var cmdStr = $"ping6 -c4 {gateip} | grep avg | awk '{{print $4}}'|cut -d/ -f2";
|
||||
var cmd = RunCmd(cmdStr);
|
||||
if (!string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
if (float.TryParse(cmd, out float delay))
|
||||
{
|
||||
dns64List.Add(gateip, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dns64List.Keys.ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region BBR
|
||||
private bool CheckKernelVersionBBR(string kernelVer)
|
||||
{
|
||||
string[] linuxKernelCompared = kernelVer.Split('.');
|
||||
if (int.Parse(linuxKernelCompared[0]) > 4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (int.Parse(linuxKernelCompared[0]) < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (int.Parse(linuxKernelCompared[0]) == 4)
|
||||
{
|
||||
if (int.Parse(linuxKernelCompared[1]) >= 9)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (int.Parse(linuxKernelCompared[1]) < 9)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
protected void EnableBBR()
|
||||
{
|
||||
var osVersion = RunCmd("uname -r");
|
||||
var canInstallBBR = CheckKernelVersionBBR(osVersion.Split('-')[0]);
|
||||
|
||||
var bbrInfo = RunCmd("sysctl net.ipv4.tcp_congestion_control | grep bbr");
|
||||
var installed = bbrInfo.Contains("bbr");
|
||||
if (canInstallBBR && !installed)
|
||||
{
|
||||
RunCmd(@"bash -c 'echo ""net.core.default_qdisc=fq"" >> /etc/sysctl.conf'");
|
||||
RunCmd(@"bash -c 'echo ""net.ipv4.tcp_congestion_control=bbr"" >> /etc/sysctl.conf'");
|
||||
RunCmd(@"sysctl -p");
|
||||
|
||||
if (OnlyIpv6)
|
||||
{
|
||||
RemoveNat64();
|
||||
}
|
||||
WriteOutput("BBR启动成功");
|
||||
}
|
||||
|
||||
if (!canInstallBBR)
|
||||
{
|
||||
WriteOutput("****** 系统不满足启用BBR条件,启动失败。 ******");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 安装证书
|
||||
/// </summary>
|
||||
/// <param name="certPath"></param>
|
||||
/// <param name="keyPath"></param>
|
||||
protected void InstallCert(string dirPath, string certName, string keyName)
|
||||
{
|
||||
string certPath = Path.Combine(dirPath, certName);
|
||||
string keyPath = Path.Combine(dirPath, keyName);
|
||||
|
||||
// 安装依赖
|
||||
RunCmd(GetInstallCmd("socat"));
|
||||
|
||||
// 解决搬瓦工CentOS缺少问题
|
||||
RunCmd(GetInstallCmd("automake autoconf libtool"));
|
||||
|
||||
// 安装Acme
|
||||
var result = RunCmd($"curl https://get.acme.sh yes | sh");
|
||||
if (result.Contains("Install success"))
|
||||
{
|
||||
WriteOutput("安装 acme.sh 成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutput("安装 acme.sh 失败,请联系开发者!");
|
||||
throw new Exception("安装 acme.sh 失败,请联系开发者!");
|
||||
}
|
||||
|
||||
RunCmd("cd ~/.acme.sh/");
|
||||
RunCmd("alias acme.sh=~/.acme.sh/acme.sh");
|
||||
|
||||
// 申请证书
|
||||
if (OnlyIpv6)
|
||||
{
|
||||
var cmd = $"/root/.acme.sh/acme.sh --force --debug --issue --standalone -d {Parameters.Domain} --listen-v6";
|
||||
result = RunCmd(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cmd = $"/root/.acme.sh/acme.sh --force --debug --issue --standalone -d {Parameters.Domain}";
|
||||
result = RunCmd(cmd);
|
||||
}
|
||||
|
||||
if (result.Contains("success"))
|
||||
{
|
||||
WriteOutput("申请证书成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutput("申请证书失败,如果申请次数过多请更换二级域名,或联系开发者!");
|
||||
throw new Exception("申请证书失败,如果申请次数过多请更换二级域名,或联系开发者!");
|
||||
}
|
||||
|
||||
// 安装证书
|
||||
RunCmd($"mkdir -p {dirPath}");
|
||||
RunCmd($"/root/.acme.sh/acme.sh --installcert -d {Parameters.Domain} --certpath {certPath} --keypath {keyPath} --capath {certPath}");
|
||||
|
||||
result = RunCmd($@"if [ ! -f ""{keyPath}"" ]; then echo ""0""; else echo ""1""; fi | head -n 1");
|
||||
|
||||
if (result.Contains("1"))
|
||||
{
|
||||
WriteOutput("安装证书成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutput("安装证书失败,请联系开发者!");
|
||||
throw new Exception("安装证书失败,请联系开发者!");
|
||||
}
|
||||
|
||||
RunCmd($"chmod 755 {dirPath}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="path"></param>
|
||||
protected void UploadFile(Stream stream, string path)
|
||||
{
|
||||
using (var sftp = new SftpClient(_sshClient.ConnectionInfo))
|
||||
{
|
||||
sftp.Connect();
|
||||
sftp.UploadFile(stream, path, true);
|
||||
sftp.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据系统环境匹配更新命令
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetUpdateCmd()
|
||||
{
|
||||
if (CmdType == CmdType.Apt)
|
||||
{
|
||||
return "apt-get update";
|
||||
}
|
||||
else if (CmdType == CmdType.Dnf)
|
||||
{
|
||||
return "dnf clean all;dnf makecache";
|
||||
}
|
||||
else if (CmdType == CmdType.Yum)
|
||||
{
|
||||
return "yum clean all;yum makecache";
|
||||
}
|
||||
|
||||
throw new Exception("未识别的系统");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据系统匹配安装命令
|
||||
/// </summary>
|
||||
/// <param name="soft"></param>
|
||||
/// <returns></returns>
|
||||
protected string GetInstallCmd(string soft)
|
||||
{
|
||||
if (CmdType == CmdType.Apt)
|
||||
{
|
||||
return "echo y | apt-get install " + soft;
|
||||
}
|
||||
else if (CmdType == CmdType.Dnf)
|
||||
{
|
||||
return "echo y | dnf -y install " + soft;
|
||||
}
|
||||
else if (CmdType == CmdType.Yum)
|
||||
{
|
||||
return "echo y | yum -y install " + soft;
|
||||
}
|
||||
|
||||
throw new Exception("未识别的系统");
|
||||
}
|
||||
}
|
||||
}
|
64
ProxySuper.Core/Services/TrojanGoConfigBuilder.cs
Normal file
64
ProxySuper.Core/Services/TrojanGoConfigBuilder.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using ProxySuper.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Services
|
||||
{
|
||||
public class TrojanGoConfigBuilder
|
||||
{
|
||||
public static readonly int WebPort = 8088;
|
||||
|
||||
public static readonly string TrojanGoSettingPath = @"Templates\trojan-go\trojan-go.json";
|
||||
|
||||
public static readonly string CaddyFilePath = @"Templates\trojan-go\base.caddyfile";
|
||||
|
||||
public static string BuildTrojanGoConfig(TrojanGoSettings parameters)
|
||||
{
|
||||
var jsonStr = File.ReadAllText(TrojanGoSettingPath);
|
||||
var settings = JToken.FromObject(JsonConvert.DeserializeObject(jsonStr));
|
||||
|
||||
settings["remote_port"] = WebPort;
|
||||
settings["password"][0] = parameters.Password;
|
||||
settings["ssl"]["sni"] = parameters.Domain;
|
||||
|
||||
return JsonConvert.SerializeObject(settings, Formatting.Indented, new JsonSerializerSettings()
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
});
|
||||
}
|
||||
|
||||
public static string BuildCaddyConfig(TrojanGoSettings parameters, bool useCustomWeb = false)
|
||||
{
|
||||
var caddyStr = File.ReadAllText(CaddyFilePath);
|
||||
caddyStr.Replace("##domain##", parameters.Domain);
|
||||
caddyStr.Replace("##port##", WebPort.ToString());
|
||||
|
||||
if (!useCustomWeb && !string.IsNullOrEmpty(parameters.MaskDomain))
|
||||
{
|
||||
var prefix = "http://";
|
||||
if (parameters.MaskDomain.StartsWith("https://"))
|
||||
{
|
||||
prefix = "https://";
|
||||
}
|
||||
var domain = parameters.MaskDomain
|
||||
.TrimStart("http://".ToCharArray())
|
||||
.TrimStart("https://".ToCharArray());
|
||||
|
||||
caddyStr = caddyStr.Replace("##reverse_proxy##", $"reverse_proxy {prefix}{domain} {{ \n header_up Host {domain} \n }}");
|
||||
}
|
||||
else
|
||||
{
|
||||
caddyStr = caddyStr.Replace("##reverse_proxy##", "");
|
||||
}
|
||||
|
||||
return caddyStr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
136
ProxySuper.Core/Services/TrojanGoProject.cs
Normal file
136
ProxySuper.Core/Services/TrojanGoProject.cs
Normal file
@ -0,0 +1,136 @@
|
||||
using ProxySuper.Core.Models;
|
||||
using Renci.SshNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace ProxySuper.Core.Services
|
||||
{
|
||||
public class TrojanGoProject : ProjectBase<TrojanGoSettings>
|
||||
{
|
||||
public TrojanGoProject(SshClient sshClient, TrojanGoSettings parameters, Action<string> writeOutput) : base(sshClient, parameters, writeOutput)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Install()
|
||||
{
|
||||
try
|
||||
{
|
||||
EnsureRootAuth();
|
||||
|
||||
if (FileExists("/usr/local/bin/xray"))
|
||||
{
|
||||
var btnResult = MessageBox.Show("已经安装Xray,是否需要重装?", "提示", MessageBoxButton.YesNo);
|
||||
if (btnResult == MessageBoxResult.No)
|
||||
{
|
||||
MessageBox.Show("安装终止", "提示");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WriteOutput("检测安装系统环境...");
|
||||
EnsureSystemEnv();
|
||||
WriteOutput("检测安装系统环境完成");
|
||||
|
||||
WriteOutput("配置服务器端口...");
|
||||
ConfigurePort();
|
||||
WriteOutput("端口配置完成");
|
||||
|
||||
WriteOutput("安装必要的系统工具...");
|
||||
ConfigureSoftware();
|
||||
WriteOutput("系统工具安装完成");
|
||||
|
||||
WriteOutput("检测IP6...");
|
||||
ConfigureIPv6();
|
||||
WriteOutput("检测IP6完成");
|
||||
|
||||
WriteOutput("配置防火墙...");
|
||||
ConfigureFirewall();
|
||||
WriteOutput("防火墙配置完成");
|
||||
|
||||
WriteOutput("同步系统和本地时间...");
|
||||
SyncTimeDiff();
|
||||
WriteOutput("时间同步完成");
|
||||
|
||||
WriteOutput("检测域名是否绑定本机IP...");
|
||||
ValidateDomain();
|
||||
WriteOutput("域名检测完成");
|
||||
|
||||
WriteOutput("安装Trojan-Go...");
|
||||
InstallTrojanGo();
|
||||
WriteOutput("Trojan-Go安装完成");
|
||||
|
||||
WriteOutput("安装Caddy...");
|
||||
InstallCaddy();
|
||||
WriteOutput("Caddy安装完成");
|
||||
|
||||
WriteOutput("启动BBR");
|
||||
EnableBBR();
|
||||
|
||||
UploadCaddyFile();
|
||||
WriteOutput("************");
|
||||
WriteOutput("安装完成,尽情享用吧......");
|
||||
WriteOutput("************");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorLog = "安装终止," + ex.Message;
|
||||
WriteOutput(errorLog);
|
||||
MessageBox.Show(errorLog);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallTrojanGo()
|
||||
{
|
||||
WriteOutput("安装Trojan-Go");
|
||||
RunCmd(@"curl https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh yes | bash");
|
||||
var success = FileExists("/usr/local/etc/trojan-go");
|
||||
if (success == false)
|
||||
{
|
||||
throw new Exception("trojan-go 安装失败,请联系开发者!");
|
||||
}
|
||||
|
||||
RunCmd($"sed -i 's/User=nobody/User=root/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"sed -i 's/CapabilityBoundingSet=/#CapabilityBoundingSet=/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"sed -i 's/AmbientCapabilities=/#AmbientCapabilities=/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"systemctl daemon-reload");
|
||||
|
||||
RunCmd("systemctl enable trojan-go");
|
||||
RunCmd("systemctl start trojan-go");
|
||||
WriteOutput("Trojan-Go 安装完成");
|
||||
|
||||
InstallCert(
|
||||
dirPath: "/usr/local/etc/trojan-go",
|
||||
certName: "trojan-go.crt",
|
||||
keyName: "trojan-go.key");
|
||||
|
||||
if (FileExists("/usr/local/etc/trojan-go/config.json"))
|
||||
{
|
||||
RunCmd("mv /usr/local/etc/trojan-go/config.json config.json.old");
|
||||
}
|
||||
|
||||
// 上传配置
|
||||
var settings = TrojanGoConfigBuilder.BuildTrojanGoConfig(Parameters);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(settings));
|
||||
UploadFile(stream, "/usr/local/etc/trojan-go/config.json");
|
||||
RunCmd("systemctl restart trojan-go");
|
||||
}
|
||||
|
||||
private void UploadCaddyFile(bool useCustomWeb = false)
|
||||
{
|
||||
var config = TrojanGoConfigBuilder.BuildCaddyConfig(Parameters, useCustomWeb);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(config));
|
||||
if (FileExists("/etc/caddy/Caddyfile"))
|
||||
{
|
||||
RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back");
|
||||
}
|
||||
UploadFile(stream, "/etc/caddy/Caddyfile");
|
||||
RunCmd("systemctl restart caddy");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
234
ProxySuper.Core/Services/XrayConfigBuilder.cs
Normal file
234
ProxySuper.Core/Services/XrayConfigBuilder.cs
Normal file
@ -0,0 +1,234 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using ProxySuper.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxySuper.Core.Services
|
||||
{
|
||||
public class XrayConfigBuilder
|
||||
{
|
||||
private const string ServerLogDir = @"Templates\xray\server\00_log";
|
||||
private const string ServerApiDir = @"Templates\xray\server\01_api";
|
||||
private const string ServerDnsDir = @"Templates\xray\server\02_dns";
|
||||
private const string ServerRoutingDir = @"Templates\xray\server\03_routing";
|
||||
private const string ServerPolicyDir = @"Templates\xray\server\04_policy";
|
||||
private const string ServerInboundsDir = @"Templates\xray\server\05_inbounds";
|
||||
private const string ServerOutboundsDir = @"Templates\xray\server\06_outbounds";
|
||||
private const string ServerTransportDir = @"Templates\xray\server\07_transport";
|
||||
private const string ServerStatsDir = @"Templates\xray\server\08_stats";
|
||||
private const string ServerReverseDir = @"Templates\xray\server\09_reverse";
|
||||
private const string CaddyFileDir = @"Templates\xray\caddy";
|
||||
|
||||
public static int VLESS_TCP_Port = 1110;
|
||||
public static int VLESS_WS_Port = 1111;
|
||||
public static int VLESS_H2_Port = 1112;
|
||||
public static int VLESS_mKCP_Port = 1113;
|
||||
|
||||
public static int VMESS_TCP_Port = 1210;
|
||||
public static int VMESS_WS_Port = 1211;
|
||||
public static int VMESS_H2_Port = 1212;
|
||||
|
||||
public static int Trojan_TCP_Port = 1310;
|
||||
public static int Trojan_WS_Port = 1311;
|
||||
|
||||
public static int FullbackPort = 8080;
|
||||
|
||||
|
||||
|
||||
public static dynamic LoadXrayConfig()
|
||||
{
|
||||
dynamic logObj = LoadJsonObj(Path.Combine(ServerLogDir, "00_log.json"));
|
||||
dynamic apiObj = LoadJsonObj(Path.Combine(ServerApiDir, "01_api.json"));
|
||||
dynamic dnsObj = LoadJsonObj(Path.Combine(ServerDnsDir, "02_dns.json"));
|
||||
dynamic routingObj = LoadJsonObj(Path.Combine(ServerRoutingDir, "03_routing.json"));
|
||||
dynamic policyObj = LoadJsonObj(Path.Combine(ServerPolicyDir, "04_policy.json"));
|
||||
dynamic inboundsObj = LoadJsonObj(Path.Combine(ServerInboundsDir, "05_inbounds.json"));
|
||||
dynamic outboundsObj = LoadJsonObj(Path.Combine(ServerOutboundsDir, "06_outbounds.json"));
|
||||
dynamic transportObj = LoadJsonObj(Path.Combine(ServerTransportDir, "07_transport.json"));
|
||||
dynamic statsObj = LoadJsonObj(Path.Combine(ServerStatsDir, "08_stats.json"));
|
||||
dynamic reverseObj = LoadJsonObj(Path.Combine(ServerReverseDir, "09_reverse.json"));
|
||||
|
||||
return new
|
||||
{
|
||||
log = logObj["log"],
|
||||
//api = apiObj["api"], api不能为空
|
||||
dns = dnsObj["dns"],
|
||||
routing = routingObj["routing"],
|
||||
policy = policyObj["policy"],
|
||||
inbounds = inboundsObj["inbounds"],
|
||||
outbounds = outboundsObj["outbounds"],
|
||||
transport = transportObj["transport"],
|
||||
stats = statsObj["stats"],
|
||||
reverse = reverseObj["reverse"]
|
||||
};
|
||||
}
|
||||
|
||||
public static string BuildCaddyConfig(XraySettings parameters, bool useCustomWeb = false)
|
||||
{
|
||||
var caddyStr = File.ReadAllText(Path.Combine(CaddyFileDir, "base.caddyfile"));
|
||||
caddyStr = caddyStr.Replace("##domain##", parameters.Domain);
|
||||
caddyStr = caddyStr.Replace("##port##", FullbackPort.ToString());
|
||||
|
||||
if (!useCustomWeb && !string.IsNullOrEmpty(parameters.MaskDomain))
|
||||
{
|
||||
var prefix = "http://";
|
||||
if (parameters.MaskDomain.StartsWith("https://"))
|
||||
{
|
||||
prefix = "https://";
|
||||
}
|
||||
var domain = parameters.MaskDomain
|
||||
.TrimStart("http://".ToCharArray())
|
||||
.TrimStart("https://".ToCharArray());
|
||||
|
||||
caddyStr = caddyStr.Replace("##reverse_proxy##", $"reverse_proxy {prefix}{domain} {{ \n header_up Host {domain} \n }}");
|
||||
}
|
||||
else
|
||||
{
|
||||
caddyStr = caddyStr.Replace("##reverse_proxy##", "");
|
||||
}
|
||||
|
||||
return caddyStr;
|
||||
}
|
||||
|
||||
public static string BuildXrayConfig(XraySettings parameters)
|
||||
{
|
||||
var xrayConfig = LoadXrayConfig();
|
||||
var baseBound = GetBound("VLESS_TCP_XTLS.json");
|
||||
baseBound.port = parameters.Port;
|
||||
baseBound.settings.fallbacks.Add(JToken.FromObject(new
|
||||
{
|
||||
dest = FullbackPort
|
||||
}));
|
||||
xrayConfig.inbounds.Add(baseBound);
|
||||
baseBound.settings.clients[0].id = parameters.UUID;
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VLESS_WS))
|
||||
{
|
||||
var wsInbound = GetBound("VLESS_WS.json");
|
||||
wsInbound.port = VLESS_WS_Port;
|
||||
wsInbound.settings.clients[0].id = parameters.UUID;
|
||||
wsInbound.streamSettings.wsSettings.path = parameters.VLESS_WS_Path;
|
||||
baseBound.settings.fallbacks.Add(JToken.FromObject(new
|
||||
{
|
||||
dest = VLESS_WS_Port,
|
||||
path = parameters.VLESS_WS_Path,
|
||||
xver = 1,
|
||||
}));
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(wsInbound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VLESS_gRPC))
|
||||
{
|
||||
var gRPCInBound = GetBound("VLESS_gRPC.json");
|
||||
gRPCInBound.port = parameters.VLESS_gRPC_Port;
|
||||
gRPCInBound.settings.clients[0].id = parameters.UUID;
|
||||
gRPCInBound.streamSettings.grpcSettings.serviceName = parameters.VLESS_gRPC_ServiceName;
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(gRPCInBound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VLESS_KCP))
|
||||
{
|
||||
var kcpBound = GetBound("VLESS_KCP.json");
|
||||
kcpBound.port = parameters.VLESS_KCP_Port;
|
||||
kcpBound.settings.clients[0].id = parameters.UUID;
|
||||
kcpBound.streamSettings.kcpSettings.header.type = parameters.VLESS_KCP_Type;
|
||||
kcpBound.streamSettings.kcpSettings.seed = parameters.VLESS_KCP_Seed;
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(kcpBound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VMESS_TCP))
|
||||
{
|
||||
var mtcpBound = GetBound("VMESS_TCP.json");
|
||||
mtcpBound.port = VMESS_TCP_Port;
|
||||
mtcpBound.settings.clients[0].id = parameters.UUID;
|
||||
mtcpBound.streamSettings.tcpSettings.header.request.path = parameters.VMESS_TCP_Path;
|
||||
baseBound.settings.fallbacks.Add(JToken.FromObject(new
|
||||
{
|
||||
dest = VMESS_TCP_Port,
|
||||
path = parameters.VMESS_TCP_Path,
|
||||
xver = 1,
|
||||
}));
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(mtcpBound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VMESS_WS))
|
||||
{
|
||||
var mwsBound = GetBound("VMESS_WS.json");
|
||||
mwsBound.port = VMESS_WS_Port;
|
||||
mwsBound.settings.clients[0].id = parameters.UUID;
|
||||
mwsBound.streamSettings.wsSettings.path = parameters.VMESS_WS_Path;
|
||||
baseBound.settings.fallbacks.Add(JToken.FromObject(new
|
||||
{
|
||||
dest = VMESS_WS_Port,
|
||||
path = parameters.VMESS_WS_Path,
|
||||
xver = 1,
|
||||
}));
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(mwsBound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.VMESS_KCP))
|
||||
{
|
||||
var kcpBound = GetBound("VMESS_KCP.json");
|
||||
kcpBound.port = parameters.VMESS_KCP_Port;
|
||||
kcpBound.settings.clients[0].id = parameters.UUID;
|
||||
kcpBound.streamSettings.kcpSettings.header.type = parameters.VMESS_KCP_Type;
|
||||
kcpBound.streamSettings.kcpSettings.seed = parameters.VMESS_KCP_Seed;
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(kcpBound));
|
||||
}
|
||||
|
||||
if (parameters.Types.Contains(XrayType.Trojan_TCP))
|
||||
{
|
||||
var trojanTcpBound = GetBound("Trojan_TCP.json");
|
||||
trojanTcpBound.port = Trojan_TCP_Port;
|
||||
trojanTcpBound.settings.clients[0].password = parameters.TrojanPassword;
|
||||
trojanTcpBound.settings.fallbacks[0].dest = FullbackPort;
|
||||
baseBound.settings.fallbacks[0] = JToken.FromObject(new
|
||||
{
|
||||
dest = Trojan_TCP_Port,
|
||||
xver = 1,
|
||||
});
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(trojanTcpBound));
|
||||
}
|
||||
|
||||
|
||||
if (parameters.Types.Contains(XrayType.ShadowsocksAEAD))
|
||||
{
|
||||
var ssBound = GetBound("Shadowsocks-AEAD.json");
|
||||
ssBound.port = parameters.ShadowsocksPort;
|
||||
ssBound.settings.clients[0].password = parameters.ShadowsocksPassword;
|
||||
ssBound.settings.clients[0].method = parameters.ShadowsocksMethod;
|
||||
xrayConfig.inbounds.Add(JToken.FromObject(ssBound));
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(
|
||||
xrayConfig,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings()
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
});
|
||||
}
|
||||
|
||||
private static dynamic GetBound(string name)
|
||||
{
|
||||
return LoadJsonObj(Path.Combine(ServerInboundsDir, name));
|
||||
}
|
||||
|
||||
private static dynamic LoadJsonObj(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var jsonStr = File.ReadAllText(path, Encoding.UTF8);
|
||||
return JToken.FromObject(JsonConvert.DeserializeObject(jsonStr));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
321
ProxySuper.Core/Services/XrayProject.cs
Normal file
321
ProxySuper.Core/Services/XrayProject.cs
Normal file
@ -0,0 +1,321 @@
|
||||
using Newtonsoft.Json;
|
||||
using ProxySuper.Core.Models;
|
||||
using Renci.SshNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace ProxySuper.Core.Services
|
||||
{
|
||||
public class XrayProject : ProjectBase<XraySettings>
|
||||
{
|
||||
|
||||
private const string ServerLogDir = @"Templates\xray\server\00_log";
|
||||
private const string ServerApiDir = @"Templates\xray\server\01_api";
|
||||
private const string ServerDnsDir = @"Templates\xray\server\02_dns";
|
||||
private const string ServerRoutingDir = @"Templates\xray\server\03_routing";
|
||||
private const string ServerPolicyDir = @"Templates\xray\server\04_policy";
|
||||
private const string ServerInboundsDir = @"Templates\xray\server\05_inbounds";
|
||||
private const string ServerOutboundsDir = @"Templates\xray\server\06_outbounds";
|
||||
private const string ServerTransportDir = @"Templates\xray\server\07_transport";
|
||||
private const string ServerStatsDir = @"Templates\xray\server\08_stats";
|
||||
private const string ServerReverseDir = @"Templates\xray\server\09_reverse";
|
||||
private const string CaddyFileDir = @"Templates\xray\caddy";
|
||||
|
||||
public XrayProject(SshClient sshClient, XraySettings parameters, Action<string> writeOutput) : base(sshClient, parameters, writeOutput)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装Xray
|
||||
/// </summary>
|
||||
public override void Install()
|
||||
{
|
||||
try
|
||||
{
|
||||
EnsureRootAuth();
|
||||
|
||||
if (FileExists("/usr/local/bin/xray"))
|
||||
{
|
||||
var btnResult = MessageBox.Show("已经安装Xray,是否需要重装?", "提示", MessageBoxButton.YesNo);
|
||||
if (btnResult == MessageBoxResult.No)
|
||||
{
|
||||
MessageBox.Show("安装终止", "提示");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WriteOutput("检测安装系统环境...");
|
||||
EnsureSystemEnv();
|
||||
WriteOutput("检测安装系统环境完成");
|
||||
|
||||
WriteOutput("配置服务器端口...");
|
||||
ConfigurePort();
|
||||
WriteOutput("端口配置完成");
|
||||
|
||||
WriteOutput("安装必要的系统工具...");
|
||||
ConfigureSoftware();
|
||||
WriteOutput("系统工具安装完成");
|
||||
|
||||
WriteOutput("检测IP6...");
|
||||
ConfigureIPv6();
|
||||
WriteOutput("检测IP6完成");
|
||||
|
||||
WriteOutput("配置防火墙...");
|
||||
ConfigureFirewall();
|
||||
WriteOutput("防火墙配置完成");
|
||||
|
||||
WriteOutput("同步系统和本地时间...");
|
||||
SyncTimeDiff();
|
||||
WriteOutput("时间同步完成");
|
||||
|
||||
WriteOutput("检测域名是否绑定本机IP...");
|
||||
ValidateDomain();
|
||||
WriteOutput("域名检测完成");
|
||||
|
||||
WriteOutput("安装Xray-Core...");
|
||||
InstallXrayWithCert();
|
||||
WriteOutput("Xray-Core安装完成");
|
||||
|
||||
WriteOutput("安装Caddy...");
|
||||
InstallCaddy();
|
||||
WriteOutput("Caddy安装完成");
|
||||
|
||||
WriteOutput("启动BBR");
|
||||
EnableBBR();
|
||||
|
||||
UploadCaddyFile();
|
||||
WriteOutput("************");
|
||||
WriteOutput("安装完成,尽情享用吧......");
|
||||
WriteOutput("************");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorLog = "安装终止," + ex.Message;
|
||||
WriteOutput(errorLog);
|
||||
MessageBox.Show(errorLog);
|
||||
}
|
||||
}
|
||||
|
||||
public void UninstallProxy()
|
||||
{
|
||||
EnsureRootAuth();
|
||||
WriteOutput("卸载Caddy");
|
||||
UninstallCaddy();
|
||||
WriteOutput("卸载Xray");
|
||||
UninstallXray();
|
||||
WriteOutput("卸载证书");
|
||||
UninstallAcme();
|
||||
WriteOutput("关闭端口");
|
||||
ClosePort(Parameters.ShadowsocksPort, Parameters.VMESS_KCP_Port);
|
||||
|
||||
WriteOutput("************ 卸载完成 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新xray内核
|
||||
/// </summary>
|
||||
public void UpdateXrayCore()
|
||||
{
|
||||
EnsureRootAuth();
|
||||
EnsureSystemEnv();
|
||||
RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ install");
|
||||
RunCmd("systemctl restart xray");
|
||||
WriteOutput("************ 更新xray内核完成 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新xray配置
|
||||
/// </summary>
|
||||
public void UpdateXraySettings()
|
||||
{
|
||||
EnsureRootAuth();
|
||||
EnsureSystemEnv();
|
||||
ConfigureFirewall();
|
||||
var configJson = XrayConfigBuilder.BuildXrayConfig(Parameters);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(configJson));
|
||||
RunCmd("rm -rf /usr/local/etc/xray/config.json");
|
||||
UploadFile(stream, "/usr/local/etc/xray/config.json");
|
||||
ConfigurePort();
|
||||
UploadCaddyFile(string.IsNullOrEmpty(Parameters.MaskDomain));
|
||||
RunCmd("systemctl restart xray");
|
||||
WriteOutput("************ 更新Xray配置成功,更新配置不包含域名,如果域名更换请重新安装。 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重装Caddy
|
||||
/// </summary>
|
||||
public void DoUninstallCaddy()
|
||||
{
|
||||
EnsureRootAuth();
|
||||
UninstallCaddy();
|
||||
WriteOutput("************ 卸载Caddy完成 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装证书
|
||||
/// </summary>
|
||||
public void InstallCertToXray()
|
||||
{
|
||||
EnsureRootAuth();
|
||||
EnsureSystemEnv();
|
||||
InstallCert(
|
||||
dirPath: "/usr/local/etc/xray/ssl",
|
||||
certName: "xray_ssl.crt",
|
||||
keyName: "xray_ssl.key");
|
||||
|
||||
RunCmd("systemctl restart xray");
|
||||
WriteOutput("************ 安装证书完成 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传证书
|
||||
/// </summary>
|
||||
/// <param name="keyStrem"></param>
|
||||
/// <param name="crtStream"></param>
|
||||
public void UploadCert(Stream stream)
|
||||
{
|
||||
EnsureRootAuth();
|
||||
EnsureSystemEnv();
|
||||
|
||||
// 转移旧文件
|
||||
var oldFileName = $"ssl_{DateTime.Now.Ticks}";
|
||||
RunCmd($"mv /usr/local/etc/xray/ssl /usr/local/etc/xray/{oldFileName}");
|
||||
|
||||
// 上传新文件
|
||||
RunCmd("mkdir /usr/local/etc/xray/ssl");
|
||||
UploadFile(stream, "/usr/local/etc/xray/ssl/ssl.zip");
|
||||
RunCmd("unzip /usr/local/etc/xray/ssl/ssl.zip -d /usr/local/etc/xray/ssl");
|
||||
|
||||
// 改名
|
||||
var crtFiles = RunCmd("find /usr/local/etc/xray/ssl/*.crt").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
if (crtFiles.Length > 0)
|
||||
{
|
||||
RunCmd($"mv {crtFiles[0]} /usr/local/etc/xray/ssl/xray_ssl.crt");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutput("************ 上传证书失败,请联系开发者 ************");
|
||||
RunCmd("rm -rf /usr/local/etc/xray/ssl");
|
||||
RunCmd($"mv /usr/local/etc/xray/ssl{oldFileName} /usr/local/etc/xray/ssl");
|
||||
WriteOutput("操作已回滚");
|
||||
return;
|
||||
}
|
||||
|
||||
var keyFiles = RunCmd("find /usr/local/etc/xray/ssl/*.key").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
if (keyFiles.Length > 0)
|
||||
{
|
||||
RunCmd($"mv {keyFiles[0]} /usr/local/etc/xray/ssl/xray_ssl.key");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutput("************ 上传证书失败,请联系开发者 ************");
|
||||
RunCmd("rm -rf /usr/local/etc/xray/ssl");
|
||||
RunCmd($"mv /usr/local/etc/xray/ssl{oldFileName} /usr/local/etc/xray/ssl");
|
||||
WriteOutput("操作已回滚");
|
||||
return;
|
||||
}
|
||||
|
||||
RunCmd("systemctl restart xray");
|
||||
WriteOutput("************ 上传证书完成 ************");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传静态网站
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public void UploadWeb(Stream stream)
|
||||
{
|
||||
EnsureRootAuth();
|
||||
EnsureSystemEnv();
|
||||
if (!FileExists("/usr/share/caddy"))
|
||||
{
|
||||
RunCmd("mkdir /usr/share/caddy");
|
||||
}
|
||||
RunCmd("rm -rf /usr/share/caddy/*");
|
||||
UploadFile(stream, "/usr/share/caddy/caddy.zip");
|
||||
RunCmd("unzip /usr/share/caddy/caddy.zip -d /usr/share/caddy");
|
||||
RunCmd("chmod -R 777 /usr/share/caddy");
|
||||
UploadCaddyFile(useCustomWeb: true);
|
||||
WriteOutput("************ 上传网站模板完成 ************");
|
||||
}
|
||||
|
||||
|
||||
private void UploadCaddyFile(bool useCustomWeb = false)
|
||||
{
|
||||
var configJson = XrayConfigBuilder.BuildCaddyConfig(Parameters, useCustomWeb);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(configJson));
|
||||
if (FileExists("/etc/caddy/Caddyfile"))
|
||||
{
|
||||
RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back");
|
||||
}
|
||||
UploadFile(stream, "/etc/caddy/Caddyfile");
|
||||
RunCmd("systemctl restart caddy");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UninstallXray()
|
||||
{
|
||||
RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ remove");
|
||||
}
|
||||
|
||||
private void UninstallAcme()
|
||||
{
|
||||
RunCmd("acme.sh --uninstall");
|
||||
RunCmd("rm -r ~/.acme.sh");
|
||||
}
|
||||
|
||||
private void InstallXrayWithCert()
|
||||
{
|
||||
RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ install");
|
||||
|
||||
if (!FileExists("/usr/local/bin/xray"))
|
||||
{
|
||||
WriteOutput("Xray-Core安装失败,请联系开发者");
|
||||
throw new Exception("Xray-Core安装失败,请联系开发者");
|
||||
}
|
||||
|
||||
RunCmd($"sed -i 's/User=nobody/User=root/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"sed -i 's/CapabilityBoundingSet=/#CapabilityBoundingSet=/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"sed -i 's/AmbientCapabilities=/#AmbientCapabilities=/g' /etc/systemd/system/xray.service");
|
||||
RunCmd($"systemctl daemon-reload");
|
||||
|
||||
if (FileExists("/usr/local/etc/xray/config.json"))
|
||||
{
|
||||
RunCmd(@"mv /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.1");
|
||||
}
|
||||
|
||||
WriteOutput("安装TLS证书");
|
||||
InstallCertToXray();
|
||||
WriteOutput("TLS证书安装完成");
|
||||
|
||||
|
||||
var configJson = XrayConfigBuilder.BuildXrayConfig(Parameters);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(configJson));
|
||||
UploadFile(stream, "/usr/local/etc/xray/config.json");
|
||||
RunCmd("systemctl restart xray");
|
||||
}
|
||||
|
||||
private int GetRandomPort()
|
||||
{
|
||||
var random = new Random();
|
||||
return random.Next(10001, 60000);
|
||||
}
|
||||
|
||||
private dynamic LoadJsonObj(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var jsonStr = File.ReadAllText(path, Encoding.UTF8);
|
||||
return JsonConvert.DeserializeObject(jsonStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -18,30 +18,6 @@ namespace ProxySuper.Core.ViewModels
|
||||
_navigationService = navigationService;
|
||||
}
|
||||
|
||||
private int _count = 1;
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _count, value);
|
||||
}
|
||||
}
|
||||
|
||||
public IMvxCommand PlusCommand => new MvxCommand(Plus);
|
||||
|
||||
public void Plus()
|
||||
{
|
||||
this.Count++;
|
||||
|
||||
if (this.Count >= 2)
|
||||
{
|
||||
_navigationService.Navigate<SecondViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MvvmCross" version="7.1.2" targetFramework="net461" />
|
||||
<package id="SSH.NET" version="2020.0.1" targetFramework="net461" />
|
||||
<package id="System.Console" version="4.3.1" targetFramework="net461" />
|
||||
</packages>
|
@ -7,11 +7,8 @@
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||
<!-- Theme setting -->
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
|
||||
<!--Languages-->
|
||||
<ResourceDictionary Source="/Resources/Languages/zh_cn.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
@ -1,34 +1,15 @@
|
||||
<local:MvxMetroWindow x:Class="ProxySuper.WPF.MainWindow"
|
||||
<local:MvxWindow x:Class="ProxySuper.WPF.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:ProxySuper.WPF"
|
||||
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||
xmlns:local="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="450" Width="800">
|
||||
<mah:MetroWindow.LeftWindowCommands>
|
||||
<mah:WindowCommands>
|
||||
<Button ToolTip="Open up the GitHub site">
|
||||
github
|
||||
</Button>
|
||||
</mah:WindowCommands>
|
||||
</mah:MetroWindow.LeftWindowCommands>
|
||||
FontSize="14"
|
||||
Icon="/Resources/ProxySU.ico"
|
||||
Title="主机列表" Height="600" Width="1000">
|
||||
|
||||
<mah:MetroWindow.RightWindowCommands>
|
||||
<mah:WindowCommands>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,20,0">
|
||||
<TextBlock Text="语言(Language)" VerticalAlignment="Center" Margin="0,0,20,0" />
|
||||
<ComboBox
|
||||
x:Name="cmbLanguage"
|
||||
SelectedIndex="0">
|
||||
<ComboBoxItem x:Name="zh_cn" Content="中文"></ComboBoxItem>
|
||||
<ComboBoxItem x:Name="en" Content="英文"></ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</mah:WindowCommands>
|
||||
</mah:MetroWindow.RightWindowCommands>
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</local:MvxMetroWindow>
|
||||
</local:MvxWindow>
|
||||
|
@ -19,7 +19,7 @@ namespace ProxySuper.WPF
|
||||
/// <summary>
|
||||
/// MainWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainWindow : MvxMetroWindow
|
||||
public partial class MainWindow : MvxWindow
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
|
@ -1,119 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using MahApps.Metro.Controls;
|
||||
using MvvmCross;
|
||||
using MvvmCross.Binding.BindingContext;
|
||||
using MvvmCross.Platforms.Wpf.Views;
|
||||
using MvvmCross.ViewModels;
|
||||
|
||||
namespace ProxySuper.WPF
|
||||
{
|
||||
public class MvxMetroWindow : MetroWindow, IMvxWindow, IMvxWpfView, IDisposable
|
||||
{
|
||||
private IMvxViewModel _viewModel;
|
||||
private IMvxBindingContext _bindingContext;
|
||||
private bool _unloaded = false;
|
||||
|
||||
public IMvxViewModel ViewModel
|
||||
{
|
||||
get => _viewModel;
|
||||
set
|
||||
{
|
||||
_viewModel = value;
|
||||
DataContext = value;
|
||||
BindingContext.DataContext = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Identifier { get; set; }
|
||||
|
||||
public IMvxBindingContext BindingContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_bindingContext != null)
|
||||
return _bindingContext;
|
||||
|
||||
if (Mvx.IoCProvider != null)
|
||||
this.CreateBindingContext();
|
||||
|
||||
return _bindingContext;
|
||||
}
|
||||
set => _bindingContext = value;
|
||||
}
|
||||
|
||||
public MvxMetroWindow()
|
||||
{
|
||||
Closed += MvxWindow_Closed;
|
||||
Unloaded += MvxWindow_Unloaded;
|
||||
Loaded += MvxWindow_Loaded;
|
||||
Initialized += MvxWindow_Initialized;
|
||||
}
|
||||
|
||||
private void MvxWindow_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
if (this == Application.Current.MainWindow)
|
||||
{
|
||||
(Application.Current as MvvmCross.Platforms.Wpf.Views.MvxApplication).ApplicationInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
private void MvxWindow_Closed(object sender, EventArgs e) => Unload();
|
||||
|
||||
private void MvxWindow_Unloaded(object sender, RoutedEventArgs e) => Unload();
|
||||
|
||||
private void MvxWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ViewAppearing();
|
||||
ViewModel?.ViewAppeared();
|
||||
}
|
||||
|
||||
private void Unload()
|
||||
{
|
||||
if (!_unloaded)
|
||||
{
|
||||
ViewModel?.ViewDisappearing();
|
||||
ViewModel?.ViewDisappeared();
|
||||
ViewModel?.ViewDestroy();
|
||||
_unloaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~MvxMetroWindow()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Unloaded -= MvxWindow_Unloaded;
|
||||
Loaded -= MvxWindow_Loaded;
|
||||
Closed -= MvxWindow_Closed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MvxWindow<TViewModel> : MvxWindow, IMvxWpfView<TViewModel>
|
||||
where TViewModel : class, IMvxViewModel
|
||||
{
|
||||
public new TViewModel ViewModel
|
||||
{
|
||||
get { return (TViewModel)base.ViewModel; }
|
||||
set { base.ViewModel = value; }
|
||||
}
|
||||
|
||||
public MvxFluentBindingDescriptionSet<IMvxWpfView<TViewModel>, TViewModel> CreateBindingSet()
|
||||
{
|
||||
return this.CreateBindingSet<IMvxWpfView<TViewModel>, TViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -35,15 +37,6 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ControlzEx, Version=4.0.0.0, Culture=neutral, PublicKeyToken=69f1c32f803d307e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ControlzEx.4.4.0\lib\net45\ControlzEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MahApps.Metro, Version=2.0.0.0, Culture=neutral, PublicKeyToken=51482d6f650b2b3f, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MahApps.Metro.2.4.5\lib\net46\MahApps.Metro.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.19\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MvvmCross, Version=7.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MvvmCross.7.1.2\lib\net461\MvvmCross.dll</HintPath>
|
||||
</Reference>
|
||||
@ -77,13 +70,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="MvxMetroWindow .cs" />
|
||||
<Compile Include="Views\MainView.xaml.cs">
|
||||
<DependentUpon>MainView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\SecondView.xaml.cs">
|
||||
<DependentUpon>SecondView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
@ -96,11 +85,17 @@
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Views\MainView.xaml">
|
||||
<Page Include="Resources\Languages\en.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\SecondView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Page>
|
||||
<Page Include="Resources\Languages\zh_cn.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Page>
|
||||
<Page Include="Views\MainView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
@ -137,5 +132,13 @@
|
||||
<Name>ProxySuper.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\ProxySU.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\Styles\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
16
ProxySuper.WPF/Resources/Languages/en.xaml
Normal file
16
ProxySuper.WPF/Resources/Languages/en.xaml
Normal file
@ -0,0 +1,16 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<sys:String x:Key="MainMenuAddHost">Add Host</sys:String>
|
||||
<sys:String x:Key="MainMenuActions">Actions</sys:String>
|
||||
<sys:String x:Key="MainMenuActionsExportSettings">Export Settings</sys:String>
|
||||
<sys:String x:Key="MainMenuActionsExportSubscribe">Export Subscribe</sys:String>
|
||||
|
||||
<sys:String x:Key="MainMenuLanguage">Language</sys:String>
|
||||
<sys:String x:Key="MainMenuLanguageEn">English</sys:String>
|
||||
<sys:String x:Key="MainMenuLanguageCn">中文</sys:String>
|
||||
|
||||
<sys:String x:Key="MainMenuHelper">Helper</sys:String>
|
||||
<sys:String x:Key="MainMenuHelperGithub">Github</sys:String>
|
||||
</ResourceDictionary>
|
17
ProxySuper.WPF/Resources/Languages/zh_cn.xaml
Normal file
17
ProxySuper.WPF/Resources/Languages/zh_cn.xaml
Normal file
@ -0,0 +1,17 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<sys:String x:Key="MainMenuAddHost">添加主机</sys:String>
|
||||
<sys:String x:Key="MainMenuActions">操作</sys:String>
|
||||
<sys:String x:Key="MainMenuActionsExportSettings">导出配置</sys:String>
|
||||
<sys:String x:Key="MainMenuActionsExportSubscribe">导出配置</sys:String>
|
||||
|
||||
<sys:String x:Key="MainMenuLanguage">语言</sys:String>
|
||||
<sys:String x:Key="MainMenuLanguageEn">English</sys:String>
|
||||
<sys:String x:Key="MainMenuLanguageCn">中文</sys:String>
|
||||
<sys:String x:Key="MainMenuHelper">帮助</sys:String>
|
||||
<sys:String x:Key="MainMenuHelperGithub">Github</sys:String>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
BIN
ProxySuper.WPF/Resources/ProxySU.ico
Normal file
BIN
ProxySuper.WPF/Resources/ProxySU.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -3,11 +3,38 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:ProxySuper.WPF.Views"
|
||||
xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
|
||||
mc:Ignorable="d" Height="450" Width="800">
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Count}" />
|
||||
<Button Command="{Binding PlusCommand}" Width="40" Height="20">+</Button>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Menu Background="White" Grid.Row="0" BorderThickness="0,0,0,2" BorderBrush="#eee">
|
||||
<MenuItem Header="{DynamicResource MainMenuAddHost}" Padding="10,3">
|
||||
<MenuItem Padding="0,5" Header="Xray"></MenuItem>
|
||||
<MenuItem Padding="0,5" Header="Trojan-Go"></MenuItem>
|
||||
<MenuItem Padding="0,5" Header="NaiveProxy"></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="{DynamicResource MainMenuActions}" Padding="10,3">
|
||||
<MenuItem Padding="0,5" Header="{DynamicResource MainMenuActionsExportSettings}"></MenuItem>
|
||||
<MenuItem Padding="0,5" Header="{DynamicResource MainMenuActionsExportSubscribe}"></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="{DynamicResource MainMenuLanguage}" Padding="10,3">
|
||||
<MenuItem Padding="0,5" Header="{DynamicResource MainMenuLanguageEn}"></MenuItem>
|
||||
<MenuItem Padding="0,5" Header="{DynamicResource MainMenuLanguageCn}"></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="{DynamicResource MainMenuHelper}" Padding="10,3">
|
||||
<MenuItem Padding="0,5" Header="{DynamicResource MainMenuHelperGithub}" Click="LaunchGitHubSite"></MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="0,10">
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</views:MvxWpfView>
|
||||
|
@ -24,5 +24,10 @@ namespace ProxySuper.WPF.Views
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void LaunchGitHubSite(object sender, RoutedEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start("explorer.exe", "https://github.com/proxysu/ProxySU");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
<local:MvxMetroWindow x:Class="ProxySuper.WPF.Views.SecondView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:ProxySuper.WPF"
|
||||
mc:Ignorable="d" Height="450" Width="800">
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Message}" />
|
||||
<Button Command="{Binding BackCommand}" Width="40" Height="20">后退</Button>
|
||||
</Grid>
|
||||
</local:MvxMetroWindow>
|
@ -1,28 +0,0 @@
|
||||
using MvvmCross.Platforms.Wpf.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace ProxySuper.WPF.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// SecondView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SecondView : MvxMetroWindow
|
||||
{
|
||||
public SecondView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ControlzEx" version="4.4.0" targetFramework="net461" />
|
||||
<package id="MahApps.Metro" version="2.4.5" targetFramework="net461" />
|
||||
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.19" targetFramework="net461" />
|
||||
<package id="MvvmCross" version="7.1.2" targetFramework="net461" />
|
||||
<package id="MvvmCross.Platforms.Wpf" version="7.1.2" targetFramework="net461" />
|
||||
<package id="System.Console" version="4.3.1" targetFramework="net461" />
|
||||
|
Loading…
Reference in New Issue
Block a user