diff --git a/ProxySuper.Core/Models/Hosts/Host.cs b/ProxySuper.Core/Models/Hosts/Host.cs index 20baa6d..eb0b2c6 100644 --- a/ProxySuper.Core/Models/Hosts/Host.cs +++ b/ProxySuper.Core/Models/Hosts/Host.cs @@ -1,5 +1,6 @@ using Microsoft.Win32; using MvvmCross.Commands; +using Newtonsoft.Json; using System.ComponentModel; using System.Threading.Tasks; using System.Windows; diff --git a/ProxySuper.Core/Models/Projects/IProjectSettings.cs b/ProxySuper.Core/Models/Projects/IProjectSettings.cs index 1570c4e..aa5eb9d 100644 --- a/ProxySuper.Core/Models/Projects/IProjectSettings.cs +++ b/ProxySuper.Core/Models/Projects/IProjectSettings.cs @@ -22,7 +22,7 @@ namespace ProxySuper.Core.Models.Projects /// /// 类型 /// - ProjectType Type { get; set; } + //ProjectType Type { get; set; } /// /// 邮箱 diff --git a/ProxySuper.Core/Models/Projects/MTProtoGoSettings.cs b/ProxySuper.Core/Models/Projects/MTProtoGoSettings.cs new file mode 100644 index 0000000..26cfabd --- /dev/null +++ b/ProxySuper.Core/Models/Projects/MTProtoGoSettings.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.Models.Projects +{ + public class MTProtoGoSettings : IProjectSettings + { + public MTProtoGoSettings() + { + Port = 443; + + Domain = string.Empty; + + Cleartext = "bing.com"; + + SecretText = string.Empty; + } + + public int Port { get; set; } + + public string Domain { get; set; } + + public List FreePorts => new List { Port }; + + public string Email => ""; + + public string Cleartext { get; set; } + + public string SecretText { get; set; } + } +} diff --git a/ProxySuper.Core/Models/Projects/ProjectType.cs b/ProxySuper.Core/Models/Projects/ProjectType.cs index 7216689..15b3e48 100644 --- a/ProxySuper.Core/Models/Projects/ProjectType.cs +++ b/ProxySuper.Core/Models/Projects/ProjectType.cs @@ -6,5 +6,7 @@ TrojanGo = 1, NaiveProxy = 2, Brook = 3, + V2ray = 4, + MTProtoGo = 5, } } diff --git a/ProxySuper.Core/Models/Projects/XrayType.cs b/ProxySuper.Core/Models/Projects/RayType.cs similarity index 94% rename from ProxySuper.Core/Models/Projects/XrayType.cs rename to ProxySuper.Core/Models/Projects/RayType.cs index 337e220..5f73e69 100644 --- a/ProxySuper.Core/Models/Projects/XrayType.cs +++ b/ProxySuper.Core/Models/Projects/RayType.cs @@ -1,6 +1,6 @@ namespace ProxySuper.Core.Models.Projects { - public enum XrayType + public enum RayType { // 入口 VLESS_TCP_XTLS = 100, @@ -25,4 +25,6 @@ // SS ShadowsocksAEAD = 401 } + + } diff --git a/ProxySuper.Core/Models/Projects/TrojanGoSettings.cs b/ProxySuper.Core/Models/Projects/TrojanGoSettings.cs index 17055fa..4462cf8 100644 --- a/ProxySuper.Core/Models/Projects/TrojanGoSettings.cs +++ b/ProxySuper.Core/Models/Projects/TrojanGoSettings.cs @@ -9,6 +9,7 @@ namespace ProxySuper.Core.Models.Projects { public TrojanGoSettings() { + WithTLS = true; Port = 443; WebSocketPath = "/ws"; Password = Guid.NewGuid().ToString(); @@ -24,6 +25,11 @@ namespace ProxySuper.Core.Models.Projects public ProjectType Type { get; set; } = ProjectType.TrojanGo; + /// + /// 是否安装TLS证书 + /// + public bool WithTLS { get; set; } + /// /// 域名 /// diff --git a/ProxySuper.Core/Models/Projects/V2raySettings.cs b/ProxySuper.Core/Models/Projects/V2raySettings.cs new file mode 100644 index 0000000..fa0bf1c --- /dev/null +++ b/ProxySuper.Core/Models/Projects/V2raySettings.cs @@ -0,0 +1,160 @@ +using Newtonsoft.Json; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; + +namespace ProxySuper.Core.Models.Projects +{ + public partial class V2raySettings : IProjectSettings + { + public V2raySettings() + { + WithTLS = true; + + var guid = Guid.NewGuid().ToString(); + Port = 443; + VLESS_KCP_Port = 2001; + VLESS_gRPC_Port = 2002; + VMESS_KCP_Port = 3001; + ShadowSocksPort = 4001; + + UUID = guid; + Types = new List(); + + VLESS_WS_Path = "/" + Utils.RandomString(6); + VLESS_KCP_Type = "none"; + VLESS_KCP_Seed = guid; + VLESS_gRPC_ServiceName = "/" + Utils.RandomString(7); + + VMESS_WS_Path = "/" + Utils.RandomString(8); + VMESS_TCP_Path = "/" + Utils.RandomString(9); + VMESS_KCP_Seed = guid; + VMESS_KCP_Type = "none"; + + TrojanPassword = guid; + + ShadowSocksPassword = guid; + ShadowSocksMethod = "aes-128-gcm"; + } + + [JsonIgnore] + public bool IsIPAddress + { + get + { + return IPAddress.TryParse(Domain, out _); + } + } + + [JsonIgnore] + public List FreePorts + { + get + { + var list = new List(); + list.Add(80); + list.Add(Port); + + if (Types.Contains(RayType.VLESS_KCP)) + { + list.Add(VLESS_KCP_Port); + } + + if (Types.Contains(RayType.VMESS_KCP)) + { + list.Add(VMESS_KCP_Port); + } + + if (Types.Contains(RayType.ShadowsocksAEAD)) + { + list.Add(ShadowSocksPort); + } + + if (Types.Contains(RayType.VLESS_gRPC)) + { + list.Add(VLESS_gRPC_Port); + } + + return list.Distinct().ToList(); + } + } + + //public ProjectType Type { get; set; } = ProjectType.Xray; + + /// + /// 是否安装证书, + /// 上传自有证书时选False,则不会自动安装证书。 + /// + public bool WithTLS { get; set; } + + /// + /// 端口 + /// + public int Port { get; set; } + + /// + /// 域名 + /// + public string Domain { get; set; } + + /// + /// UUID + /// + public string UUID { get; set; } + + /// + /// 多用户 + /// + public List MulitUUID { get; set; } = new List(); + + /// + /// 伪装域名 + /// + public string MaskDomain { get; set; } + + [JsonIgnore] + public string Email + { + get + { + if (!string.IsNullOrEmpty(Domain)) + { + var arr = Domain.Split('.'); + if (arr.Length == 3) + { + return $"{arr[0]}@{arr[1]}.{arr[2]}"; + } + } + + return $"{UUID.Substring(2, 6)}@gmail.com"; + } + } + + /// + /// 安装类型 + /// + public List Types { get; set; } = new List(); + + /// + /// 根据xray类型获取路径 + /// + /// + /// + public string GetPath(RayType type) + { + switch (type) + { + case RayType.VLESS_WS: + return VLESS_WS_Path; + case RayType.VMESS_TCP: + return VMESS_TCP_Path; + case RayType.VMESS_WS: + return VMESS_WS_Path; + default: + return string.Empty; + } + } + } +} diff --git a/ProxySuper.Core/Models/Projects/XraySettings_SS.cs b/ProxySuper.Core/Models/Projects/V2raySettings_SS.cs similarity index 83% rename from ProxySuper.Core/Models/Projects/XraySettings_SS.cs rename to ProxySuper.Core/Models/Projects/V2raySettings_SS.cs index 71936dd..945cadf 100644 --- a/ProxySuper.Core/Models/Projects/XraySettings_SS.cs +++ b/ProxySuper.Core/Models/Projects/V2raySettings_SS.cs @@ -2,7 +2,7 @@ namespace ProxySuper.Core.Models.Projects { - public partial class XraySettings + public partial class V2raySettings { /// /// ss password @@ -23,7 +23,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.ShadowsocksAEAD, this); + return ShareLink.Build(RayType.ShadowsocksAEAD, this); } } } diff --git a/ProxySuper.Core/Models/Projects/XraySettings_Trojan.cs b/ProxySuper.Core/Models/Projects/V2raySettings_Trojan.cs similarity index 70% rename from ProxySuper.Core/Models/Projects/XraySettings_Trojan.cs rename to ProxySuper.Core/Models/Projects/V2raySettings_Trojan.cs index 6d110a7..df02d34 100644 --- a/ProxySuper.Core/Models/Projects/XraySettings_Trojan.cs +++ b/ProxySuper.Core/Models/Projects/V2raySettings_Trojan.cs @@ -2,7 +2,7 @@ namespace ProxySuper.Core.Models.Projects { - public partial class XraySettings + public partial class V2raySettings { public string TrojanPassword { get; set; } @@ -10,7 +10,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.Trojan_TCP, this); + return ShareLink.Build(RayType.Trojan_TCP, this); } } } diff --git a/ProxySuper.Core/Models/Projects/XraySettings_VLESS.cs b/ProxySuper.Core/Models/Projects/V2raySettings_VLESS.cs similarity index 73% rename from ProxySuper.Core/Models/Projects/XraySettings_VLESS.cs rename to ProxySuper.Core/Models/Projects/V2raySettings_VLESS.cs index e2b959e..8bb677b 100644 --- a/ProxySuper.Core/Models/Projects/XraySettings_VLESS.cs +++ b/ProxySuper.Core/Models/Projects/V2raySettings_VLESS.cs @@ -2,19 +2,8 @@ namespace ProxySuper.Core.Models.Projects { - public partial class XraySettings + public partial class V2raySettings { - /// - /// vless xtls shareLink - /// - public string VLESS_TCP_XTLS_ShareLink - { - get - { - return ShareLink.Build(XrayType.VLESS_TCP_XTLS, this); - } - } - /// /// vless tcp shareLink /// @@ -22,7 +11,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VLESS_TCP, this); + return ShareLink.Build(RayType.VLESS_TCP, this); } } @@ -38,7 +27,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VLESS_WS, this); + return ShareLink.Build(RayType.VLESS_WS, this); } } @@ -64,7 +53,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VLESS_KCP, this); + return ShareLink.Build(RayType.VLESS_KCP, this); } } @@ -85,7 +74,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VLESS_gRPC, this); + return ShareLink.Build(RayType.VLESS_gRPC, this); } } } diff --git a/ProxySuper.Core/Models/Projects/XraySettings_VMESS.cs b/ProxySuper.Core/Models/Projects/V2raySettings_VMESS.cs similarity index 84% rename from ProxySuper.Core/Models/Projects/XraySettings_VMESS.cs rename to ProxySuper.Core/Models/Projects/V2raySettings_VMESS.cs index 61fce95..d0e2e21 100644 --- a/ProxySuper.Core/Models/Projects/XraySettings_VMESS.cs +++ b/ProxySuper.Core/Models/Projects/V2raySettings_VMESS.cs @@ -2,7 +2,7 @@ namespace ProxySuper.Core.Models.Projects { - public partial class XraySettings + public partial class V2raySettings { /// /// vmess websocket path @@ -16,7 +16,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VMESS_WS, this); + return ShareLink.Build(RayType.VMESS_WS, this); } } @@ -32,7 +32,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VMESS_TCP, this); + return ShareLink.Build(RayType.VMESS_TCP, this); } } @@ -58,7 +58,7 @@ namespace ProxySuper.Core.Models.Projects { get { - return ShareLink.Build(XrayType.VMESS_KCP, this); + return ShareLink.Build(RayType.VMESS_KCP, this); } } } diff --git a/ProxySuper.Core/Models/Projects/XraySettings.cs b/ProxySuper.Core/Models/Projects/XraySettings.cs index 709da3f..e1ed4cc 100644 --- a/ProxySuper.Core/Models/Projects/XraySettings.cs +++ b/ProxySuper.Core/Models/Projects/XraySettings.cs @@ -1,151 +1,22 @@ -using Newtonsoft.Json; -using ProxySuper.Core.Services; +using ProxySuper.Core.Services; using System; using System.Collections.Generic; using System.Linq; -using System.Net; +using System.Text; +using System.Threading.Tasks; namespace ProxySuper.Core.Models.Projects { - public partial class XraySettings : IProjectSettings + public class XraySettings : V2raySettings { - public XraySettings() - { - var guid = Guid.NewGuid().ToString(); - Port = 443; - VLESS_KCP_Port = 2001; - VLESS_gRPC_Port = 2002; - VMESS_KCP_Port = 3001; - ShadowSocksPort = 4001; - - UUID = guid; - Types = new List(); - - VLESS_WS_Path = "/" + Utils.RandomString(6); - VLESS_KCP_Type = "none"; - VLESS_KCP_Seed = guid; - VLESS_gRPC_ServiceName = "/" + Utils.RandomString(7); - - VMESS_WS_Path = "/" + Utils.RandomString(8); - VMESS_TCP_Path = "/" + Utils.RandomString(9); - VMESS_KCP_Seed = guid; - VMESS_KCP_Type = "none"; - - TrojanPassword = guid; - - ShadowSocksPassword = guid; - ShadowSocksMethod = "aes-128-gcm"; - } - - [JsonIgnore] - public bool IsIPAddress + /// + /// vless xtls shareLink + /// + public string VLESS_TCP_XTLS_ShareLink { get { - return IPAddress.TryParse(Domain, out _); - } - } - - [JsonIgnore] - public List FreePorts - { - get - { - var list = new List(); - list.Add(80); - list.Add(Port); - - if (Types.Contains(XrayType.VLESS_KCP)) - { - list.Add(VLESS_KCP_Port); - } - - if (Types.Contains(XrayType.VMESS_KCP)) - { - list.Add(VMESS_KCP_Port); - } - - if (Types.Contains(XrayType.ShadowsocksAEAD)) - { - list.Add(ShadowSocksPort); - } - - if (Types.Contains(XrayType.VLESS_gRPC)) - { - list.Add(VLESS_gRPC_Port); - } - - return list.Distinct().ToList(); - } - } - - public ProjectType Type { get; set; } = ProjectType.Xray; - - /// - /// 端口 - /// - public int Port { get; set; } - - /// - /// 域名 - /// - public string Domain { get; set; } - - /// - /// UUID - /// - public string UUID { get; set; } - - /// - /// 多用户 - /// - public List MulitUUID { get; set; } = new List(); - - /// - /// 伪装域名 - /// - public string MaskDomain { get; set; } - - [JsonIgnore] - public string Email - { - get - { - if (!string.IsNullOrEmpty(Domain)) - { - var arr = Domain.Split('.'); - if (arr.Length == 3) - { - return $"{arr[0]}@{arr[1]}.{arr[2]}"; - } - } - - return $"{UUID.Substring(2, 6)}@gmail.com"; - } - } - - /// - /// 安装类型 - /// - public List Types { get; set; } = new List(); - - /// - /// 根据xray类型获取路径 - /// - /// - /// - 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; + return ShareLink.Build(RayType.VLESS_TCP_XTLS, this); } } } diff --git a/ProxySuper.Core/Models/Record.cs b/ProxySuper.Core/Models/Record.cs index b032781..b48001e 100644 --- a/ProxySuper.Core/Models/Record.cs +++ b/ProxySuper.Core/Models/Record.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using ProxySuper.Core.Models.Hosts; using ProxySuper.Core.Models.Projects; using ProxySuper.Core.Services; +using System; using System.Text; namespace ProxySuper.Core.Models @@ -32,6 +33,9 @@ namespace ProxySuper.Core.Models } } + [JsonProperty("v2raySettings")] + public V2raySettings V2raySettings { get; set; } + [JsonProperty("settings")] public XraySettings XraySettings { get; set; } @@ -44,6 +48,9 @@ namespace ProxySuper.Core.Models [JsonProperty("brook")] public BrookSettings BrookSettings { get; set; } + [JsonProperty("mtProtoGoSettings")] + public MTProtoGoSettings MTProtoGoSettings { get; set; } + [JsonIgnore] public ProjectType Type @@ -52,10 +59,14 @@ namespace ProxySuper.Core.Models { if (XraySettings != null) return ProjectType.Xray; + if (V2raySettings != null) return ProjectType.V2ray; + if (TrojanGoSettings != null) return ProjectType.TrojanGo; if (NaiveProxySettings != null) return ProjectType.NaiveProxy; + if (MTProtoGoSettings != null) return ProjectType.MTProtoGo; + return ProjectType.Brook; } } @@ -74,8 +85,22 @@ namespace ProxySuper.Core.Models } } + [JsonIgnore] + public Action OnSave { get; set; } = () => { }; + public string GetShareLink() { + if (Type == ProjectType.V2ray) + { + StringBuilder strBuilder = new StringBuilder(); + V2raySettings.Types.ForEach(type => + { + var link = ShareLink.Build(type, V2raySettings); + strBuilder.AppendLine(link); + }); + return strBuilder.ToString(); + } + if (Type == ProjectType.Xray) { StringBuilder strBuilder = new StringBuilder(); diff --git a/ProxySuper.Core/ProxySuper.Core.csproj b/ProxySuper.Core/ProxySuper.Core.csproj index 02c6703..2b7140f 100644 --- a/ProxySuper.Core/ProxySuper.Core.csproj +++ b/ProxySuper.Core/ProxySuper.Core.csproj @@ -75,43 +75,51 @@ + - - - + + + + + - - + - - - + + + - + + + - - + + + + - + - + + + + - diff --git a/ProxySuper.Core/Services/BrookProject.cs b/ProxySuper.Core/Services/BrookProject.cs deleted file mode 100644 index 2672d84..0000000 --- a/ProxySuper.Core/Services/BrookProject.cs +++ /dev/null @@ -1,128 +0,0 @@ -using ProxySuper.Core.Models.Projects; -using Renci.SshNet; -using System; - -namespace ProxySuper.Core.Services -{ - public class BrookProject : ProjectBase - { - private string brookServiceTemp = @" - [Unit] - Description=brook service - After=network.target syslog.target - Wants=network.target - - [Service] - Type=simple - ExecStart=##run_cmd## - - [Install] - WantedBy=multi-user.target"; - - public BrookProject(SshClient sshClient, BrookSettings parameters, Action writeOutput) : base(sshClient, parameters, writeOutput) - { - } - - public override void Install() - { - - WriteOutput("检测安装系统环境..."); - EnsureSystemEnv(); - WriteOutput("检测安装系统环境完成"); - - WriteOutput("配置服务器端口..."); - ConfigFirewalld(); - WriteOutput("端口配置完成"); - - WriteOutput("安装必要的系统工具..."); - ConfigureSoftware(); - WriteOutput("系统工具安装完成"); - - WriteOutput("检测网络环境"); - EnsureIP(); - WriteOutput("检测网络环境完成"); - - if (Parameters.BrookType == BrookType.wssserver) - { - WriteOutput("检测域名是否绑定本机IP..."); - ValidateDomain(); - WriteOutput("域名检测完成"); - } - - InstallBrook(); - - - Console.WriteLine("*************安装完成,尽情享用吧**********"); - } - - public void InstallBrook() - { - Console.WriteLine("安装Brook"); - - string url = "https://github.com/txthinking/brook/releases/latest/download/brook_linux_amd64"; - if (ArchType == ArchType.arm) - { - url = url.Replace("brook_linux_amd64", "brook_linux_arm7"); - } - - RunCmd($"curl -L {url} -o /usr/bin/brook"); - RunCmd("chmod +x /usr/bin/brook"); - Console.WriteLine("安装Brook完成"); - - var brookService = brookServiceTemp.Replace("##run_cmd##", GetRunBrookCommand()); - - RunCmd("rm -rf /etc/systemd/system/brook.service"); - RunCmd("touch /etc/systemd/system/brook.service"); - RunCmd($"echo \"{brookService}\" > /etc/systemd/system/brook.service"); - RunCmd("sudo chmod 777 /etc/systemd/system/brook.service"); - - RunCmd("systemctl enable brook"); - RunCmd("systemctl restart brook"); - - WriteOutput("********************"); - WriteOutput("安装完成,尽情想用吧~ "); - WriteOutput("*********************"); - } - - private string GetRunBrookCommand() - { - var runBrookCmd = string.Empty; - - if (Parameters.BrookType == BrookType.server) - { - return $"/usr/bin/brook server --listen :{Parameters.Port} --password {Parameters.Password}"; - } - - if (Parameters.BrookType == BrookType.wsserver) - { - return $"/usr/bin/brook wsserver --listen :{Parameters.Port} --password {Parameters.Password}"; - } - - if (Parameters.BrookType == BrookType.wssserver) - { - return $"/usr/bin/brook wssserver --domain {Parameters.Domain} --password {Parameters.Password}"; - } - - if (Parameters.BrookType == BrookType.socks5) - { - var ip = OnlyIpv6 ? IPv6 : IPv4; - return $"/usr/bin/brook socks5 --socks5 {ip}:{Parameters.Port}"; - } - - return runBrookCmd; - } - - public void Uninstall() - { - RunCmd("systemctl stop brook"); - RunCmd("systemctl disable brook"); - RunCmd("rm -rf /etc/systemd/system/brook.service"); - RunCmd("rm -rf /usr/bin/brook"); - - Console.WriteLine("关闭端口"); - ResetFirewalld(); - - WriteOutput("******卸载完成******"); - } - } -} diff --git a/ProxySuper.Core/Services/BrookService.cs b/ProxySuper.Core/Services/BrookService.cs new file mode 100644 index 0000000..d5904ff --- /dev/null +++ b/ProxySuper.Core/Services/BrookService.cs @@ -0,0 +1,171 @@ +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProxySuper.Core.Services +{ + public class BrookService : ServiceBase + { + private string brookServiceTemp = @" + [Unit] + Description=brook service + After=network.target syslog.target + Wants=network.target + + [Service] + Type=simple + ExecStart=##run_cmd## + + [Install] + WantedBy=multi-user.target"; + + + public BrookService(Host host, BrookSettings settings) : base(host, settings) + { + } + + public void Install() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "安装Brook"; + Progress.Percentage = 0; + + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "安装必要的系统工具"; + InstallSystemTools(); + Progress.Percentage = 40; + + Progress.Desc = "配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 50; + + + Progress.Step = "检测网络环境"; + EnsureNetwork(); + Progress.Percentage = 60; + if (Settings.BrookType == BrookType.wssserver) + { + Progress.Desc = "检测域名是否绑定本机IP"; + ValidateDomain(); + Progress.Percentage = 80; + } + + Progress.Step = "安装Brook服务"; + InstallBrook(); + + Progress.Percentage = 100; + Progress.Step = "安装Brook成功"; + Progress.Desc = "安装Brook成功"; + + AppendCommand("分享连接:"); + AppendCommand(ShareLink.BuildBrook(Settings)); + + NavigationService.Navigate(Settings); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void InstallBrook() + { + Progress.Desc = "执行Brook安装文件"; + string url = "https://github.com/txthinking/brook/releases/latest/download/brook_linux_amd64"; + if (ArchType == ArchType.arm) + { + url = url.Replace("brook_linux_amd64", "brook_linux_arm7"); + } + + RunCmd($"curl -L {url} -o /usr/bin/brook"); + RunCmd("chmod +x /usr/bin/brook"); + + Progress.Desc = "设置Brook服务"; + var brookService = brookServiceTemp.Replace("##run_cmd##", GetRunBrookCommand()); + + RunCmd("rm -rf /etc/systemd/system/brook.service"); + RunCmd("touch /etc/systemd/system/brook.service"); + RunCmd($"echo \"{brookService}\" > /etc/systemd/system/brook.service"); + RunCmd("sudo chmod 777 /etc/systemd/system/brook.service"); + + Progress.Desc = "启动Brook服务"; + RunCmd("systemctl enable brook"); + RunCmd("systemctl restart brook"); + } + + private string GetRunBrookCommand() + { + var runBrookCmd = string.Empty; + + if (Settings.BrookType == BrookType.server) + { + return $"/usr/bin/brook server --listen :{Settings.Port} --password {Settings.Password}"; + } + + if (Settings.BrookType == BrookType.wsserver) + { + return $"/usr/bin/brook wsserver --listen :{Settings.Port} --password {Settings.Password}"; + } + + if (Settings.BrookType == BrookType.wssserver) + { + return $"/usr/bin/brook wssserver --domain {Settings.Domain} --password {Settings.Password}"; + } + + if (Settings.BrookType == BrookType.socks5) + { + var ip = IsOnlyIPv6 ? IPv6 : IPv4; + return $"/usr/bin/brook socks5 --socks5 {ip}:{Settings.Port}"; + } + + return runBrookCmd; + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "卸载Brook"; + Progress.Percentage = 0; + + Progress.Desc = "停止Brook服务"; + RunCmd("systemctl stop brook"); + RunCmd("systemctl disable brook"); + Progress.Percentage = 30; + + Progress.Desc = "删除Brook相关文件"; + RunCmd("rm -rf /etc/systemd/system/brook.service"); + RunCmd("rm -rf /usr/bin/brook"); + Progress.Percentage = 80; + + Progress.Desc = "重置防火墙设置"; + ResetFirewalld(); + + Progress.Percentage = 100; + Progress.Desc = "卸载完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + } +} diff --git a/ProxySuper.Core/Services/MTProtoGoService.cs b/ProxySuper.Core/Services/MTProtoGoService.cs new file mode 100644 index 0000000..b6992c4 --- /dev/null +++ b/ProxySuper.Core/Services/MTProtoGoService.cs @@ -0,0 +1,156 @@ +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProxySuper.Core.Services +{ + public class MTProtoGoService : ServiceBase + { + public MTProtoGoService(Host host, MTProtoGoSettings settings) : base(host, settings) + { + } + + public void Install() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "1. 检测系统环境"; + Progress.Percentage = 0; + + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 15; + + Progress.Step = "2. 安装必要的系统工具"; + InstallSystemTools(); + Progress.Percentage = 25; + + Progress.Step = "3. 配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 35; + + Progress.Step = "4. 安装docker"; + InstallDocker(); + Progress.Percentage = 50; + + Progress.Step = "5. 生成密钥"; + Settings.SecretText = RunCmd($"docker run nineseconds/mtg generate-secret {Settings.Cleartext}").TrimEnd('\n'); + Progress.Percentage = 65; + + Progress.Step = "6. 生成配置文件"; + Progress.Desc = "创建配置"; + RunCmd("touch /etc/mtg.toml"); + + Progress.Desc = "写入配置内容"; + RunCmd($"echo \"secret=\\\"{Settings.SecretText}\\\"\" > /etc/mtg.toml"); + RunCmd($"echo \"bind-to=\\\"0.0.0.0:{Settings.Port}\\\"\" >> /etc/mtg.toml"); + Progress.Percentage = 80; + + Progress.Step = "7. 启动MTProto服务"; + RunCmd($"docker run -d -v /etc/mtg.toml:/config.toml --name=mtg --restart=always -p {Settings.Port + ":" + Settings.Port} nineseconds/mtg"); + Progress.Desc = "设置自启动MTProto服务"; + + Progress.Step = "安装完成"; + Progress.Percentage = 100; + + AppendCommand("Host: " + Settings.Domain); + AppendCommand("Port: " + Settings.Port); + AppendCommand("Secret: " + Settings.SecretText); + + NavigationService.Navigate(Settings); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Percentage = 0; + Progress.Step = "卸载MTProto"; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + Progress.Percentage = 30; + + Progress.Desc = "删除docker容器"; + var cid = RunCmd("docker ps -q --filter name=mtg"); + RunCmd($"docker stop {cid}"); + RunCmd($"docker rm {cid}"); + Progress.Percentage = 100; + Progress.Desc = "卸载完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateSettings() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Percentage = 0; + Progress.Step = "更新MTProto配置"; + + Progress.Desc = "暂停MTProto服务"; + var cid = RunCmd("docker ps -q --filter name=mtg"); + RunCmd($"docker stop {cid}"); + Progress.Percentage = 50; + + Progress.Desc = "生成密钥"; + Settings.SecretText = RunCmd($"docker run nineseconds/mtg generate-secret {Settings.Cleartext}").TrimEnd('\n'); + Progress.Percentage = 65; + + Progress.Desc = "修改配置文件"; + RunCmd($"echo \"secret=\\\"{Settings.SecretText}\\\"\" > /etc/mtg.toml"); + RunCmd($"echo \"bind-to=\\\"0.0.0.0:{Settings.Port}\\\"\" >> /etc/mtg.toml"); + Progress.Percentage = 80; + + Progress.Desc = "重启MTProto服务"; + RunCmd($"docker restart {cid}"); + + Progress.Percentage = 100; + Progress.Desc = "更新配置成功"; + + AppendCommand("Host: " + Settings.Domain); + AppendCommand("Port: " + Settings.Port); + AppendCommand("Secret: " + Settings.SecretText); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void InstallDocker() + { + Progress.Desc = "执行docker安装脚本"; + RunCmd("yes | curl https://get.docker.com | sh"); + + if (!FileExists("/usr/bin/docker")) + { + Progress.Desc = "docker安装失败"; + throw new Exception("docker安装失败"); + } + } + } +} diff --git a/ProxySuper.Core/Services/NaiveProxyProject.cs b/ProxySuper.Core/Services/NaiveProxyProject.cs deleted file mode 100644 index 0f9f7d9..0000000 --- a/ProxySuper.Core/Services/NaiveProxyProject.cs +++ /dev/null @@ -1,168 +0,0 @@ -using ProxySuper.Core.Models.Projects; -using Renci.SshNet; -using System; -using System.IO; -using System.Text; -using System.Windows; - -namespace ProxySuper.Core.Services -{ - public class NaiveProxyProject : ProjectBase - { - public NaiveProxyProject(SshClient sshClient, NaiveProxySettings parameters, Action writeOutput) : base(sshClient, parameters, writeOutput) - { - } - - public void Uninstall() - { - 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"); - WriteOutput("ProxyNaive卸载完成"); - } - - 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("************ 上传网站模板完成 ************"); - } - - public override void Install() - { - try - { - EnsureRootAuth(); - - WriteOutput("检测安装系统环境..."); - EnsureSystemEnv(); - WriteOutput("检测安装系统环境完成"); - - WriteOutput("安装必要的系统工具..."); - ConfigureSoftware(); - WriteOutput("系统工具安装完成"); - - WriteOutput("配置防火墙..."); - ConfigFirewalld(); - WriteOutput("防火墙配置完成"); - - WriteOutput("检测网络环境"); - EnsureIP(); - WriteOutput("检测网络环境完成"); - - WriteOutput("同步系统和本地时间..."); - SyncTimeDiff(); - WriteOutput("时间同步完成"); - - WriteOutput("检测域名是否绑定本机IP..."); - ValidateDomain(); - WriteOutput("域名检测完成"); - - WriteOutput("安装NaiveProxy..."); - InstallNaiveProxy(); - WriteOutput("NaiveProxy安装完成"); - - WriteOutput("启动BBR"); - EnableBBR(); - - WriteOutput("************"); - WriteOutput("安装完成,尽情享用吧......"); - WriteOutput("************"); - } - catch (Exception ex) - { - var errorLog = "安装终止," + ex.Message; - WriteOutput(errorLog); - MessageBox.Show("安装失败,请联系开发者或上传日志文件(Logs文件夹下)到github提问。"); - } - } - - private void InstallNaiveProxy() - { - WriteOutput("安装 NaiveProxy"); - RunCmd(@"curl https://raw.githubusercontent.com/proxysu/shellscript/master/Caddy-Naive/caddy-naive-install.sh yes | bash"); - // 允许开机启动 - RunCmd("systemctl enable caddy"); - UploadCaddyFile(false); - ConfigNetwork(); - WriteOutput("NaiveProxy 安装完成"); - } - - private void ConfigNetwork() - { - WriteOutput("优化网络参数"); - RunCmd(@"bash -c 'echo ""fs.file-max = 51200"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.rmem_max = 67108864"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.wmem_max = 67108864"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.rmem_default = 65536"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.wmem_default = 65536"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.netdev_max_backlog = 4096"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.core.somaxconn = 4096"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_syncookies = 1"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_tw_reuse = 1"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_tw_recycle = 0"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_fin_timeout = 30"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_keepalive_time = 1200"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.ip_local_port_range = 10000 65000"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_max_syn_backlog = 4096"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_max_tw_buckets = 5000"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_rmem = 4096 87380 67108864"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_wmem = 4096 65536 67108864"" >> /etc/sysctl.conf'"); - RunCmd(@"bash -c 'echo ""net.ipv4.tcp_mtu_probing = 1"" >> /etc/sysctl.conf'"); - RunCmd(@"sysctl -p"); - WriteOutput("网络参数优化完成"); - } - - private void UploadCaddyFile(bool useCustomWeb = false) - { - var caddyStr = BuildConfig(useCustomWeb); - - if (FileExists("/etc/caddy/Caddyfile")) - { - RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back"); - } - - RunCmd($"echo {caddyStr} > /etc/caddy/Caddyfile"); - RunCmd("systemctl restart caddy"); - } - - private string BuildConfig(bool useCustomWeb = false) - { - var jsonStr = File.ReadAllText("Templates/NaiveProxy/naive_server.caddyfile"); - jsonStr = jsonStr.Replace("##port##", Parameters.Port.ToString()); - jsonStr = jsonStr.Replace("##domain##", Parameters.Domain); - jsonStr = jsonStr.Replace("##basicauth##", $"basic_auth {Parameters.UserName} {Parameters.Password}"); - - 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()); - - jsonStr = jsonStr.Replace("##reverse_proxy##", $"reverse_proxy {prefix}{domain} {{ \n header_up Host {domain} \n }}"); - } - else - { - jsonStr = jsonStr.Replace("##reverse_proxy##", ""); - jsonStr = jsonStr.Replace("#file_server", "file_server"); - } - return jsonStr; - } - } -} diff --git a/ProxySuper.Core/Services/NaiveProxyService.cs b/ProxySuper.Core/Services/NaiveProxyService.cs new file mode 100644 index 0000000..47980f5 --- /dev/null +++ b/ProxySuper.Core/Services/NaiveProxyService.cs @@ -0,0 +1,282 @@ +using Microsoft.Win32; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProxySuper.Core.Services +{ + public class NaiveProxyService : ServiceBase + { + public NaiveProxyService(Host host, NaiveProxySettings settings) : base(host, settings) + { + } + + public void Install() + { + Task.Factory.StartNew(() => + { + try + { + var index = 1; + + Progress.Step = $"{index++}. 检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Step = $"{index++}. 安装系统必要工具"; + InstallSystemTools(); + Progress.Percentage = 30; + + Progress.Step = $"{index++}. 配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 40; + + Progress.Step = $"{index++}. 检测网络环境"; + EnsureNetwork(); + Progress.Percentage = 50; + + Progress.Step = $"{index++}. 检测域名是否绑定到本机"; + ValidateDomain(); + Progress.Percentage = 60; + + Progress.Step = $"{index++}. 安装NaiveProxy"; + InstallNaiveProxy(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 优化网络参数"; + ConfigNetwork(); + Progress.Percentage = 90; + + Progress.Step = $"{index++}. 启动BBR"; + EnableBBR(); + + Progress.Desc = "重启Caddy服务"; + RunCmd("systemctl restart caddy"); + + Progress.Percentage = 100; + Progress.Step = "NaiveProxy安装成功"; + Progress.Desc = string.Empty; + + AppendCommand("分享连接:"); + AppendCommand(ShareLink.BuildNaiveProxy(Settings)); + + NavigationService.Navigate(Settings); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "卸载NaiveProxy"; + Progress.Percentage = 0; + + Progress.Desc = "正在卸载..."; + RunCmd("rm -rf caddy_install.sh"); + Progress.Percentage = 10; + + RunCmd("curl -o caddy_install.sh https://raw.githubusercontent.com/proxysu/shellscript/master/Caddy-Naive/caddy-naive-install.sh"); + Progress.Percentage = 20; + + RunCmd("yes | bash caddy_install.sh uninstall"); + Progress.Percentage = 80; + + RunCmd("rm -rf caddy_install.sh"); + Progress.Percentage = 100; + Progress.Step = "卸载NaiveProxy成功"; + Progress.Desc = "卸载NaiveProxy成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateSettings() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新配置"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 30; + + UploadCaddySettings(); + Progress.Desc = "重启Caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 100; + + Progress.Step = "更新配置成功"; + Progress.Desc = string.Empty; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UploadWeb() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadWeb; + fileDialog.ShowDialog(); + } + + + #region 私有方法 + + private void DoUploadWeb(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Step = "上传静态网站"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "创建网站目录"; + if (!FileExists("/usr/share/caddy")) + { + RunCmd("mkdir /usr/share/caddy"); + } + RunCmd("rm -rf /usr/share/caddy/*"); + Progress.Percentage = 40; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + 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"); + Progress.Percentage = 700; + } + + Progress.Desc = "上传Caddy配置文件"; + UploadCaddySettings(useCustomWeb: true); + Progress.Percentage = 90; + + Progress.Desc = "重启caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 100; + Progress.Desc = "上传静态网站成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void InstallNaiveProxy() + { + Progress.Desc = "下载NaiveProxy安装文件"; + RunCmd(@"curl https://raw.githubusercontent.com/proxysu/shellscript/master/Caddy-Naive/caddy-naive-install.sh yes | bash"); + + Progress.Desc = "设置NaiveProxy开机启动"; + RunCmd("systemctl enable caddy"); + + Progress.Desc = "上传配置文件"; + UploadCaddySettings(false); + } + + private void ConfigNetwork() + { + RunCmd(@"bash -c 'echo ""fs.file-max = 51200"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.rmem_max = 67108864"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.wmem_max = 67108864"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.rmem_default = 65536"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.wmem_default = 65536"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.netdev_max_backlog = 4096"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.core.somaxconn = 4096"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_syncookies = 1"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_tw_reuse = 1"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_tw_recycle = 0"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_fin_timeout = 30"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_keepalive_time = 1200"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.ip_local_port_range = 10000 65000"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_max_syn_backlog = 4096"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_max_tw_buckets = 5000"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_rmem = 4096 87380 67108864"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_wmem = 4096 65536 67108864"" >> /etc/sysctl.conf'"); + RunCmd(@"bash -c 'echo ""net.ipv4.tcp_mtu_probing = 1"" >> /etc/sysctl.conf'"); + RunCmd(@"sysctl -p"); + } + + private void UploadCaddySettings(bool useCustomWeb = false) + { + Progress.Desc = "生成配置文件"; + var caddyStr = BuildConfig(useCustomWeb); + + if (FileExists("/etc/caddy/Caddyfile")) + { + RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back"); + } + + Progress.Desc = "上传配置文件"; + WriteToFile(caddyStr, "/etc/caddy/Caddyfile"); + } + + private string BuildConfig(bool useCustomWeb = false) + { + var jsonStr = File.ReadAllText("Templates/NaiveProxy/naive_server.caddyfile"); + jsonStr = jsonStr.Replace("##port##", Settings.Port.ToString()); + jsonStr = jsonStr.Replace("##domain##", Settings.Domain); + jsonStr = jsonStr.Replace("##basicauth##", $"basic_auth {Settings.UserName} {Settings.Password}"); + + if (!useCustomWeb && !string.IsNullOrEmpty(Settings.MaskDomain)) + { + var prefix = "http://"; + if (Settings.MaskDomain.StartsWith("https://")) + { + prefix = "https://"; + } + var domain = Settings.MaskDomain + .TrimStart("http://".ToCharArray()) + .TrimStart("https://".ToCharArray()); + + jsonStr = jsonStr.Replace("##reverse_proxy##", $"reverse_proxy {prefix}{domain} {{ \n header_up Host {domain} \n }}"); + } + else + { + jsonStr = jsonStr.Replace("##reverse_proxy##", ""); + jsonStr = jsonStr.Replace("#file_server", "file_server"); + } + return jsonStr; + } + + #endregion + } +} diff --git a/ProxySuper.Core/Services/ProjectBase.cs b/ProxySuper.Core/Services/ProjectBase.cs deleted file mode 100644 index 983fcf2..0000000 --- a/ProxySuper.Core/Services/ProjectBase.cs +++ /dev/null @@ -1,855 +0,0 @@ -using ProxySuper.Core.Helpers; -using ProxySuper.Core.Models; -using ProxySuper.Core.Models.Hosts; -using ProxySuper.Core.Models.Projects; -using Renci.SshNet; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Windows; - -namespace ProxySuper.Core.Services -{ - public enum CmdType - { - None, - Apt, - Dnf, - Yum - } - - public enum ArchType - { - x86, - arm, - } - - public abstract class ProjectBase where TSettings : IProjectSettings - { - - - private SshClient _sshClient; - - protected Action WriteOutput; - - protected CmdType CmdType { get; set; } - - protected ArchType ArchType { 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 writeOutput) - { - _sshClient = sshClient; - WriteOutput = writeOutput; - Parameters = parameters; - } - - protected string RunCmd(string cmdStr) - { - var cmd = _sshClient.CreateCommand(cmdStr); - WriteOutput(cmdStr); - - var exe = cmd.BeginExecute(); - var result = cmd.EndExecute(exe); - //var result = cmd.Execute(); - WriteOutput(result); - return result; - } - - /// - /// 执行安装命令 - /// - public abstract void Install(); - - /// - /// 配置系统基础环境 - /// - protected void EnsureSystemEnv() - { - string cmd; - - // cpu架构 - var result = RunCmd("uname -m"); - if (result.Contains("x86")) - { - ArchType = ArchType.x86; - } - else if (result.Contains("arm") || result.Contains("arch")) - { - ArchType = ArchType.arm; - } - else - { - throw new Exception($"未识别的架构处理器架构:{result}"); - } - - // 确认安装命令 - if (CmdType == CmdType.None) - { - cmd = RunCmd("command -v apt"); - if (!string.IsNullOrEmpty(cmd)) - { - CmdType = CmdType.Apt; - } - } - - if (CmdType == CmdType.None) - { - cmd = RunCmd("command -v dnf"); - if (!string.IsNullOrEmpty(cmd)) - { - CmdType = CmdType.Dnf; - //RunCmd("echo \"export LC_ALL=en_US.UTF-8\" >> /etc/profile"); - //RunCmd("source /etc/profile"); - } - } - - 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||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"); - } - } - } - - /// - /// 确保Root账户登陆 - /// - 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账户登陆主机"); - } - } - - /// - /// 配置IPV6环境 - /// - protected void EnsureIP() - { - if (IsOnlyIpv6()) - { - SetNat64(); - } - } - - /// - /// 配置必要的软件 - /// - protected void ConfigureSoftware() - { - RunCmd(GetUpdateCmd()); - - 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(GetInstallCmd("dnsutils")); - } - else if (CmdType == CmdType.Dnf) - { - RunCmd(GetInstallCmd("bind-utils")); - } - else if (CmdType == CmdType.Yum) - { - RunCmd(GetInstallCmd("bind-utils")); - } - } - - - // 处理极其少见的xz-utils未安装的情况 - if (CmdType == CmdType.Apt) - { - RunCmd(GetInstallCmd("xz-utils")); - } - else - { - RunCmd(GetInstallCmd("xz-devel")); - } - - // 检测是否安装cron - cmd = RunCmd("command -v cron"); - if (string.IsNullOrEmpty(cmd)) - { - RunCmd(GetInstallCmd("cron")); - } - - // 检测是否安装lsof - cmd = RunCmd("command -v lsof"); - if (string.IsNullOrEmpty(cmd)) - { - RunCmd(GetInstallCmd("lsof")); - } - } - - /// - /// 配置防火墙 - /// - protected void ConfigFirewalld() - { - Parameters.FreePorts.ForEach(port => - { - SetPortFree(port); - }); - - OpenPort(_sshClient.ConnectionInfo.Port); - OpenPort(Parameters.FreePorts.ToArray()); - } - - /// - /// 重置防火墙 - /// - protected void ResetFirewalld() - { - Parameters.FreePorts.ForEach(port => - { - SetPortFree(port); - }); - ClosePort(Parameters.FreePorts.ToArray()); - } - - /// - /// 配置同步时间差 - /// - 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()})\""); - } - } - - /// - /// 验证域名是否绑定了主机 - /// - 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($"域名解析失败,安装停止!"); - } - - } - - /// - /// 判断是否安装某个软件 - /// - /// - /// - 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"; - } - - /// - /// 安装 Caddy - /// - protected void InstallCaddy() - { - #region 二进制文件安装 - RunCmd("rm -rf caddy.tar.gz"); - RunCmd("rm -rf /etc/caddy"); - RunCmd("rm -rf /usr/share/caddy"); - - var url = "https://github.com/caddyserver/caddy/releases/download/v2.4.3/caddy_2.4.3_linux_amd64.tar.gz"; - if (ArchType == ArchType.arm) - { - url = "https://github.com/caddyserver/caddy/releases/download/v2.4.3/caddy_2.4.3_linux_armv7.tar.gz"; - } - - RunCmd($"wget -O caddy.tar.gz {url}"); - RunCmd("mkdir /etc/caddy"); - RunCmd("tar -zxvf caddy.tar.gz -C /etc/caddy"); - RunCmd("cp -rf /etc/caddy/caddy /usr/bin"); - WriteToFile(Caddy.DefaultCaddyFile, "/etc/caddy/Caddyfile"); - WriteToFile(Caddy.Service, "/etc/systemd/system/caddy.service"); - RunCmd("systemctl daemon-reload"); - RunCmd("systemctl enable caddy"); - - RunCmd("mkdir /usr/share/caddy"); - - if (!FileExists("/usr/bin/caddy")) - { - throw new Exception("Caddy服务器安装失败,请联系开发者!"); - } - #endregion - - #region 官方安装步骤 - //if (CmdType == CmdType.Apt) - //{ - // RunCmd("apt install -y debian-keyring debian-archive-keyring apt-transport-https"); - // RunCmd("echo yes | curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo apt-key add -"); - // RunCmd("echo yes | curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list"); - // RunCmd("sudo apt -y update"); - // RunCmd("sudo apt install -y caddy"); - //} - - //if (CmdType == CmdType.Dnf) - //{ - // RunCmd("dnf install -y 'dnf-command(copr)'"); - // RunCmd("dnf copr -y enable @caddy/caddy"); - // RunCmd("dnf install -y caddy"); - //} - - //if (CmdType == CmdType.Yum) - //{ - // RunCmd("yum install -y yum-plugin-copr"); - // RunCmd("yum copr -y enable @caddy/caddy"); - // RunCmd("yum install -y caddy"); - //} - - //RunCmd("systemctl enable caddy.service"); - #endregion - } - - /// - /// 卸载 Caddy - /// - protected void UninstallCaddy() - { - RunCmd("systemctl stop caddy"); - RunCmd("systemctl disable caddy"); - RunCmd("rm -rf /etc/systemd/system/caddy.service"); - RunCmd("rm -rf /usr/bin/caddy"); - RunCmd("rm -rf /usr/share/caddy"); - RunCmd("rm -rf /etc/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; - } - - 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 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 dns64List = new Dictionary(); - 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(); - } - - 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; - } - - /// - /// 关闭端口 - /// - /// - private 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"); - } - } - } - - /// - /// 开放端口 - /// - /// - private 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)) - { - RunCmd(GetInstallCmd("ufw")); - RunCmd("echo y | ufw enable"); - } - - foreach (var port in portList) - { - RunCmd($"ufw allow {port}/tcp"); - RunCmd($"ufw allow {port}/udp"); - } - RunCmd("yes | ufw reload"); - - } - } - - #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 - - /// - /// 安装证书 - /// - /// - /// - protected void InstallCert(string dirPath, string certName, string keyName) - { - string certPath = dirPath + "/" + certName; - string keyPath = 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("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 --pre-hook \"systemctl stop caddy\" --post-hook \"systemctl start caddy\" --server letsencrypt"; - result = RunCmd(cmd); - } - else - { - var cmd = $"/root/.acme.sh/acme.sh --force --debug --issue --standalone -d {Parameters.Domain} --pre-hook \"systemctl stop caddy\" --post-hook \"systemctl start caddy\" --server letsencrypt"; - 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}"); - } - - protected void WriteToFile(string text, string path) - { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(text))) - { - using (var sftp = new SftpClient(_sshClient.ConnectionInfo)) - { - try - { - sftp.Connect(); - sftp.UploadFile(stream, path, true); - } - catch (Exception ex) - { - throw ex; - } - finally - { - sftp.Disconnect(); - } - } - } - } - - /// - /// 上传文件 - /// - /// - /// - protected void UploadFile(Stream stream, string path) - { - using (var sftp = new SftpClient(_sshClient.ConnectionInfo)) - { - sftp.Connect(); - sftp.UploadFile(stream, path, true); - sftp.Disconnect(); - } - } - - /// - /// 根据系统环境匹配更新命令 - /// - /// - protected string GetUpdateCmd() - { - if (CmdType == CmdType.Apt) - { - return "apt update"; - } - else if (CmdType == CmdType.Dnf) - { - RunCmd("echo \"export LC_ALL=en_US.UTF-8\" >> /etc/profile"); - RunCmd("source /etc/profile"); - return "dnf clean all;dnf makecache"; - } - else if (CmdType == CmdType.Yum) - { - RunCmd("echo \"export LC_ALL=en_US.UTF-8\" >> /etc/profile"); - RunCmd("source /etc/profile"); - return "yum clean all;yum makecache"; - } - - throw new Exception("未识别的系统"); - } - - /// - /// 根据系统匹配安装命令 - /// - /// - /// - protected string GetInstallCmd(string soft) - { - if (CmdType == CmdType.Apt) - { - return "apt install -y " + soft; - } - else if (CmdType == CmdType.Dnf) - { - return "dnf install -y " + soft; - } - else if (CmdType == CmdType.Yum) - { - return "yum install -y " + soft; - } - - throw new Exception("未识别的系统"); - } - } -} diff --git a/ProxySuper.Core/Services/ServiceBase.cs b/ProxySuper.Core/Services/ServiceBase.cs index 3d9aad7..75f677a 100644 --- a/ProxySuper.Core/Services/ServiceBase.cs +++ b/ProxySuper.Core/Services/ServiceBase.cs @@ -1,4 +1,6 @@ -using ProxySuper.Core.Helpers; +using MvvmCross; +using MvvmCross.Navigation; +using ProxySuper.Core.Helpers; using ProxySuper.Core.Models; using ProxySuper.Core.Models.Hosts; using ProxySuper.Core.Models.Projects; @@ -9,14 +11,29 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Navigation; namespace ProxySuper.Core.Services { + public enum ArchType + { + x86, + arm + } + + public enum CmdType + { + None, + Yum, + Apt, + Dnf + } + public abstract class ServiceBase where TSettings : IProjectSettings { private Host _host; - private SshClient _sshClient; private ProjectProgress _progress; @@ -27,7 +44,11 @@ namespace ProxySuper.Core.Services Settings = settings; - _sshClient = new SshClient(CreateConnectionInfo()); + var connection = CreateConnectionInfo(); + if (connection != null) + { + _sshClient = new SshClient(connection); + } _progress = new ProjectProgress(); @@ -40,6 +61,8 @@ namespace ProxySuper.Core.Services IPv6 = string.Empty; IsOnlyIPv6 = false; + + NavigationService = Mvx.IoCProvider.Resolve(); } public string RunCmd(string command) @@ -75,12 +98,20 @@ namespace ProxySuper.Core.Services public bool IsOnlyIPv6 { get; set; } + public IMvxNavigationService NavigationService { get; set; } + #region 公用方法 public void Connect() { Task.Run(() => { + if (_sshClient == null) + { + MessageBox.Show("无法建立连接,连接参数有误!"); + return; + } + if (_sshClient.IsConnected == false) { Progress.Desc = ("正在与服务器建立连接"); @@ -101,7 +132,7 @@ namespace ProxySuper.Core.Services { Task.Run(() => { - _sshClient.Disconnect(); + _sshClient?.Disconnect(); }); } @@ -258,7 +289,7 @@ namespace ProxySuper.Core.Services #endregion // 安装证书 - Progress.Desc = ("安装Xray证书"); + Progress.Desc = ("安装TLS证书"); RunCmd($"mkdir -p {dirPath}"); RunCmd($"/root/.acme.sh/acme.sh --installcert -d {Settings.Domain} --certpath {certPath} --keypath {keyPath} --capath {certPath}"); @@ -277,15 +308,40 @@ namespace ProxySuper.Core.Services RunCmd($"chmod 755 {dirPath}"); } + protected void UploadFile(Stream stream, string path) + { + using (var sftp = new SftpClient(_sshClient.ConnectionInfo)) + { + sftp.Connect(); + sftp.UploadFile(stream, path, true); + sftp.Disconnect(); + } + } - public bool IsRootUser() + public void EnsureRootUser() { // 禁止一些可能产生的干扰信息 RunCmd(@"sed -i 's/echo/#echo/g' ~/.bashrc"); RunCmd(@"sed -i 's/echo/#echo/g' ~/.profile"); var result = RunCmd("id -u"); - return result.Equals("0\n"); + if (!result.Equals("0\n")) + { + throw new Exception("ProxySU需要使用Root用户进行安装!"); + } + } + + public void UninstallCaddy() + { + Progress.Desc = "关闭Caddy服务"; + RunCmd("systemctl stop caddy"); + RunCmd("systemctl disable caddy"); + + Progress.Desc = "彻底删除Caddy文件"; + RunCmd("rm -rf /etc/systemd/system/caddy.service"); + RunCmd("rm -rf /usr/bin/caddy"); + RunCmd("rm -rf /usr/share/caddy"); + RunCmd("rm -rf /etc/caddy"); } public void EnsureSystemEnv() @@ -343,6 +399,11 @@ namespace ProxySuper.Core.Services OpenPort(Settings.FreePorts.ToArray()); } + public void ResetFirewalld() + { + ClosePort(Settings.FreePorts.ToArray()); + } + public void EnsureNetwork() { string cmd; @@ -516,6 +577,15 @@ namespace ProxySuper.Core.Services RunCmd("mv /etc/resolv.conf.proxysu /etc/resolv.conf"); } + protected void AppendCommand(string command) + { + if (!command.EndsWith("\n")) + { + command += "\n"; + } + Progress.Logs += command; + } + private List FilterFastestIP() { string[] gateNat64 = { @@ -606,6 +676,8 @@ namespace ProxySuper.Core.Services RunCmd("systemctl restart firewalld"); } + // 保持 ssh 端口开放 + RunCmd($"firewall-cmd --add-port={_host.Port}/tcp --permanent"); foreach (var port in portList) { RunCmd($"firewall-cmd --add-port={port}/tcp --permanent"); @@ -623,6 +695,8 @@ namespace ProxySuper.Core.Services RunCmd("echo y | ufw enable"); } + // 保持 ssh 端口开放 + RunCmd($"ufw allow {_host.Port}/tcp"); foreach (var port in portList) { RunCmd($"ufw allow {port}/tcp"); @@ -694,46 +768,56 @@ namespace ProxySuper.Core.Services } } - private void AppendCommand(string command) - { - if (!command.EndsWith("\n")) - { - command += "\n"; - } - Progress.Logs += command; - } private ConnectionInfo CreateConnectionInfo() { - var authMethods = new List(); - - if (!string.IsNullOrEmpty(_host.Password)) + try { - authMethods.Add(new PasswordAuthenticationMethod(_host.UserName, _host.Password)); - } + var authMethods = new List(); - if (_host.SecretType == LoginSecretType.PrivateKey) - { - authMethods.Add(new PrivateKeyAuthenticationMethod(_host.UserName, new PrivateKeyFile(_host.PrivateKeyPath))); - } + if (_host.SecretType == LoginSecretType.Password) + { + authMethods.Add(new PasswordAuthenticationMethod(_host.UserName, _host.Password)); + } + + if (_host.SecretType == LoginSecretType.PrivateKey) + { + PrivateKeyFile keyFile; + if (string.IsNullOrEmpty(_host.Password)) + { + keyFile = new PrivateKeyFile(_host.PrivateKeyPath); + } + else + { + keyFile = new PrivateKeyFile(_host.PrivateKeyPath, _host.Password); + } + authMethods.Add(new PrivateKeyAuthenticationMethod(_host.UserName, keyFile)); + } + + if (_host.Proxy.Type == ProxyTypes.None) + { + return new ConnectionInfo( + host: _host.Address, + username: _host.UserName, + port: _host.Port, + authenticationMethods: authMethods.ToArray()); + } - if (_host.Proxy.Type == ProxyTypes.None) - { return new ConnectionInfo( host: _host.Address, - username: _host.Password, + port: _host.Port, + username: _host.UserName, + proxyType: _host.Proxy.Type, + proxyHost: _host.Proxy.Address, + proxyPort: _host.Proxy.Port, + proxyUsername: _host.Proxy.UserName, proxyPassword: _host.Proxy.Password, authenticationMethods: authMethods.ToArray()); } - - return new ConnectionInfo( - host: _host.Address, - port: _host.Port, - username: _host.UserName, - proxyType: _host.Proxy.Type, - proxyHost: _host.Proxy.Address, - proxyPort: _host.Proxy.Port, - proxyUsername: _host.Proxy.UserName, proxyPassword: _host.Proxy.Password, - authenticationMethods: authMethods.ToArray()); + catch (Exception ex) + { + MessageBox.Show(ex.Message); + return null; + } } #endregion } diff --git a/ProxySuper.Core/Services/ShareLink.cs b/ProxySuper.Core/Services/ShareLink.cs index 00992e1..b892100 100644 --- a/ProxySuper.Core/Services/ShareLink.cs +++ b/ProxySuper.Core/Services/ShareLink.cs @@ -69,30 +69,30 @@ namespace ProxySuper.Core.Services return strBuilder.ToString(); } - public static string Build(XrayType xrayType, XraySettings settings) + public static string Build(RayType xrayType, V2raySettings settings) { switch (xrayType) { - case XrayType.VLESS_TCP: - case XrayType.VLESS_TCP_XTLS: - case XrayType.VLESS_WS: - case XrayType.VLESS_KCP: - case XrayType.VLESS_gRPC: - case XrayType.Trojan_TCP: + case RayType.VLESS_TCP: + case RayType.VLESS_TCP_XTLS: + case RayType.VLESS_WS: + case RayType.VLESS_KCP: + case RayType.VLESS_gRPC: + case RayType.Trojan_TCP: return BuildVlessShareLink(xrayType, settings); - case XrayType.VMESS_TCP: - case XrayType.VMESS_WS: - case XrayType.VMESS_KCP: + case RayType.VMESS_TCP: + case RayType.VMESS_WS: + case RayType.VMESS_KCP: return BuildVmessShareLink(xrayType, settings); - case XrayType.ShadowsocksAEAD: + case RayType.ShadowsocksAEAD: return BuildShadowSocksShareLink(settings); default: return string.Empty; } } - private static string BuildShadowSocksShareLink(XraySettings settings) + private static string BuildShadowSocksShareLink(V2raySettings settings) { var _method = settings.ShadowSocksMethod; var _password = settings.ShadowSocksPassword; @@ -103,7 +103,7 @@ namespace ProxySuper.Core.Services return "ss://" + base64URL + "#ShadowSocks"; } - private static string BuildVmessShareLink(XrayType xrayType, XraySettings settings) + private static string BuildVmessShareLink(RayType xrayType, V2raySettings settings) { var vmess = new Vmess { @@ -122,19 +122,19 @@ namespace ProxySuper.Core.Services switch (xrayType) { - case XrayType.VMESS_TCP: + case RayType.VMESS_TCP: vmess.ps = "vmess-tcp-tls"; vmess.net = "tcp"; vmess.type = "http"; vmess.path = settings.VMESS_TCP_Path; break; - case XrayType.VMESS_WS: + case RayType.VMESS_WS: vmess.ps = "vmess-ws-tls"; vmess.net = "ws"; vmess.type = "none"; vmess.path = settings.VMESS_WS_Path; break; - case XrayType.VMESS_KCP: + case RayType.VMESS_KCP: vmess.ps = "vmess-mKCP"; vmess.port = settings.VMESS_KCP_Port.ToString(); vmess.net = "kcp"; @@ -150,7 +150,7 @@ namespace ProxySuper.Core.Services return $"vmess://" + base64Url; } - private static string BuildVlessShareLink(XrayType xrayType, XraySettings settings) + private static string BuildVlessShareLink(RayType xrayType, V2raySettings settings) { var _protocol = string.Empty; var _uuid = settings.UUID; @@ -167,24 +167,24 @@ namespace ProxySuper.Core.Services switch (xrayType) { - case XrayType.VLESS_TCP: + case RayType.VLESS_TCP: _protocol = "vless"; _type = "tcp"; _descriptiveText = "vless-tcp-tls"; break; - case XrayType.VLESS_TCP_XTLS: + case RayType.VLESS_TCP_XTLS: _protocol = "vless"; _type = "tcp"; _security = "xtls"; _descriptiveText = "vless-tcp-xtls"; break; - case XrayType.VLESS_WS: + case RayType.VLESS_WS: _protocol = "vless"; _type = "ws"; _path = settings.VLESS_WS_Path; _descriptiveText = "vless-ws-tls"; break; - case XrayType.VLESS_KCP: + case RayType.VLESS_KCP: _protocol = "vless"; _type = "kcp"; _headerType = settings.VLESS_KCP_Type; @@ -193,13 +193,13 @@ namespace ProxySuper.Core.Services _security = "none"; _descriptiveText = "vless-mKCP"; break; - case XrayType.VLESS_gRPC: + case RayType.VLESS_gRPC: _protocol = "vless"; _type = "grpc"; _port = settings.VLESS_gRPC_Port; _descriptiveText = "vless-gRPC"; break; - case XrayType.Trojan_TCP: + case RayType.Trojan_TCP: _protocol = "trojan"; _uuid = settings.TrojanPassword; _descriptiveText = "trojan-tcp"; @@ -210,25 +210,25 @@ namespace ProxySuper.Core.Services string parametersURL = string.Empty; - if (xrayType != XrayType.Trojan_TCP) + if (xrayType != RayType.Trojan_TCP) { // 4.3 传输层相关段 parametersURL = $"?type={_type}&encryption={_encryption}&security={_security}&path={HttpUtility.UrlEncode(_path)}&headerType={_headerType}"; // kcp - if (xrayType == XrayType.VLESS_KCP) + if (xrayType == RayType.VLESS_KCP) { parametersURL += $"&seed={_seed}"; } // 4.4 TLS 相关段 - if (xrayType == XrayType.VLESS_TCP_XTLS) + if (xrayType == RayType.VLESS_TCP_XTLS) { parametersURL += "&flow=xtls-rprx-direct"; } - if (xrayType == XrayType.VLESS_gRPC) + if (xrayType == RayType.VLESS_gRPC) { parametersURL += $"&serviceName={settings.VLESS_gRPC_ServiceName}&mode=gun"; } diff --git a/ProxySuper.Core/Services/TrojanGoProject.cs b/ProxySuper.Core/Services/TrojanGoProject.cs deleted file mode 100644 index bfa21e7..0000000 --- a/ProxySuper.Core/Services/TrojanGoProject.cs +++ /dev/null @@ -1,181 +0,0 @@ -using ProxySuper.Core.Models.Projects; -using Renci.SshNet; -using System; -using System.IO; -using System.Text; -using System.Windows; - -namespace ProxySuper.Core.Services -{ - public class TrojanGoProject : ProjectBase - { - public TrojanGoProject(SshClient sshClient, TrojanGoSettings parameters, Action writeOutput) : base(sshClient, parameters, writeOutput) - { - } - - public void InstallCertToTrojanGo() - { - EnsureRootAuth(); - EnsureSystemEnv(); - InstallCert( - dirPath: "/usr/local/etc/trojan-go", - certName: "trojan-go.crt", - keyName: "trojan-go.key"); - - RunCmd("systemctl restart trojan-go"); - WriteOutput("************ 安装证书完成 ************"); - } - - 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("************ 上传网站模板完成 ************"); - } - - public void Uninstall() - { - EnsureRootAuth(); - EnsureSystemEnv(); - - RunCmd("systemctl stop trojan-go"); - base.UninstallCaddy(); - - RunCmd("rm -rf /usr/local/bin/trojan-go"); - RunCmd("rm -rf /usr/local/etc/trojan-go"); - - RunCmd("acme.sh --uninstall"); - RunCmd("rm -r ~/.acme.sh"); - - WriteOutput("卸载Trojan-Go完成"); - } - - public override void Install() - { - try - { - EnsureRootAuth(); - - if (FileExists("/usr/local/bin/trojan-go")) - { - var btnResult = MessageBox.Show("已经安装Trojan-Go,是否需要重装?", "提示", MessageBoxButton.YesNo); - if (btnResult == MessageBoxResult.No) - { - MessageBox.Show("安装终止", "提示"); - return; - } - } - - WriteOutput("检测安装系统环境..."); - EnsureSystemEnv(); - WriteOutput("检测安装系统环境完成"); - - WriteOutput("安装必要的系统工具..."); - ConfigureSoftware(); - WriteOutput("系统工具安装完成"); - - WriteOutput("配置防火墙..."); - ConfigFirewalld(); - WriteOutput("防火墙配置完成"); - - WriteOutput("检测网络环境"); - EnsureIP(); - WriteOutput("检测网络环境完成"); - - WriteOutput("同步系统和本地时间..."); - SyncTimeDiff(); - WriteOutput("时间同步完成"); - - WriteOutput("检测域名是否绑定本机IP..."); - ValidateDomain(); - WriteOutput("域名检测完成"); - - WriteOutput("安装Caddy..."); - InstallCaddy(); - UploadCaddyFile(); - WriteOutput("Caddy安装完成"); - - WriteOutput("安装Trojan-Go..."); - InstallTrojanGo(); - WriteOutput("Trojan-Go安装完成"); - - - WriteOutput("启动BBR"); - EnableBBR(); - - RunCmd("systemctl restart trojan-go"); - WriteOutput("************"); - WriteOutput("安装完成,尽情享用吧......"); - WriteOutput("************"); - } - catch (Exception ex) - { - var errorLog = "安装终止," + ex.Message; - WriteOutput(errorLog); - MessageBox.Show("安装失败,请联系开发者或上传日志文件(Logs文件夹下)到github提问。"); - } - } - - private void InstallTrojanGo() - { - RunCmd(@"curl https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh yes | bash"); - var success = FileExists("/usr/local/bin/trojan-go"); - if (success == false) - { - throw new Exception("trojan-go 安装失败,请联系开发者!"); - } - - RunCmd($"sed -i 's/User=nobody/User=root/g' /etc/systemd/system/trojan-go.service"); - RunCmd($"sed -i 's/CapabilityBoundingSet=/#CapabilityBoundingSet=/g' /etc/systemd/system/trojan-go.service"); - RunCmd($"sed -i 's/AmbientCapabilities=/#AmbientCapabilities=/g' /etc/systemd/system/trojan-go.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"); - } - - UploadTrojanGoSettings(); - } - - private void UploadTrojanGoSettings() - { - // 上传配置 - 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"); - } - } - -} diff --git a/ProxySuper.Core/Services/TrojanGoService.cs b/ProxySuper.Core/Services/TrojanGoService.cs new file mode 100644 index 0000000..11264be --- /dev/null +++ b/ProxySuper.Core/Services/TrojanGoService.cs @@ -0,0 +1,401 @@ +using Microsoft.Win32; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProxySuper.Core.Services +{ + public class TrojanGoService : ServiceBase + { + public TrojanGoService(Host host, TrojanGoSettings settings) : base(host, settings) + { + } + + public void Install() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Percentage = 0; + Progress.Step = "安装TrojanGo"; + Progress.Desc = "安装TrojanGo"; + EnsureRootUser(); + + if (FileExists("/usr/local/bin/trojan-go")) + { + var btnResult = MessageBox.Show("已经安装Trojan-Go,是否需要重装?", "提示", MessageBoxButton.YesNo); + if (btnResult == MessageBoxResult.No) + { + MessageBox.Show("安装终止", "提示"); + return; + } + } + + var index = 1; + Progress.Step = $"{index++}. 检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 10; + + Progress.Step = $"{index++}. 安装必要的系统工具"; + InstallSystemTools(); + Progress.Percentage = 30; + + Progress.Step = $"{index++}. 配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 40; + + Progress.Step = $"{index++}. 检测网络环境"; + EnsureNetwork(); + Progress.Percentage = 50; + + Progress.Step = $"{index++}. 检测域名是否解析到本机"; + ValidateDomain(); + Progress.Percentage = 60; + + Progress.Step = $"{index++}. 安装Caddy服务"; + InstallCaddy(); + Progress.Percentage = 70; + + Progress.Step = $"{index++}. 安装TrojanGo"; + InstallTrojanGo(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 上传Caddy配置文件"; + UploadCaddySettings(); + Progress.Percentage = 90; + + Progress.Step = $"{index++}. 启动BBR"; + EnableBBR(); + + Progress.Step = $"{index++}. 重启caddy服务"; + RunCmd("systemctl restart caddy"); + + Progress.Desc = "启用Trojan-Go开机启动"; + RunCmd("systemctl enable trojan-go"); + RunCmd("systemctl restart trojan-go"); + + AppendCommand("分享连接:"); + AppendCommand(ShareLink.BuildTrojanGo(Settings)); + + Progress.Percentage = 100; + Progress.Step = "安装成功"; + Progress.Desc = string.Empty; + + if (!Settings.WithTLS) + { + Progress.Step = "安装成功,请上传您的 TLS 证书。"; + } + else + { + NavigationService.Navigate(Settings); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Step = "卸载Trojgan-Go"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "停止Trojan—Go服务"; + RunCmd("systemctl stop trojan-go"); + Progress.Percentage = 40; + + + Progress.Desc = "卸载Caddy"; + UninstallCaddy(); + Progress.Percentage = 60; + + Progress.Desc = "卸载Trojan-Go"; + RunCmd("rm -rf /usr/local/bin/trojan-go"); + RunCmd("rm -rf /usr/local/etc/trojan-go"); + Progress.Percentage = 90; + + Progress.Desc = "删除 acme.sh"; + RunCmd("acme.sh --uninstall"); + RunCmd("rm -r ~/.acme.sh"); + + Progress.Percentage = 100; + Progress.Step = "卸载Trojan-Go成功"; + Progress.Desc = string.Empty; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateSettings() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新配置文件"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 30; + + Progress.Desc = "更新配置文件"; + UploadTrojanGoSettings(); + Progress.Percentage = 70; + + Progress.Desc = "重启caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 80; + + Progress.Desc = "重启Trojan-Go服务器"; + RunCmd("systemctl restart trojan-go"); + + Progress.Percentage = 100; + Progress.Desc = "更新配置成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UploadWeb() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadWeb; + fileDialog.ShowDialog(); + } + + public void UploadCert() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadCert; + fileDialog.ShowDialog(); + } + + public void ApplyForCert() + { + Task.Factory.StartNew(() => + { + try + { + + Progress.Step = "续签证书"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "安装TLS证书"; + InstallCert( + dirPath: "/usr/local/etc/trojan-go", + certName: "trojan-go.crt", + keyName: "trojan-go.key"); + Progress.Percentage = 90; + + Progress.Desc = "重启Trojan-go服务"; + RunCmd("systemctl restart trojan-go"); + + Progress.Percentage = 100; + Progress.Step = "续签证书成功"; + Progress.Desc = "续签证书成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + #region 私有方法 + + + private void DoUploadCert(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Percentage = 0; + Progress.Step = "上传自有证书"; + Progress.Desc = "检测系统环境"; + + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + var oldFileName = $"ssl_{DateTime.Now.Ticks}"; + RunCmd($"mv /usr/local/etc/trojan-go/ssl /usr/local/etc/trojan-go/{oldFileName}"); + + RunCmd("mkdir /usr/local/etc/trojan-go/ssl"); + UploadFile(stream, "/usr/local/etc/trojan-go/ssl/ssl.zip"); + RunCmd("unzip /usr/local/etc/trojan-go/ssl/ssl.zip -d /usr/local/etc/trojan-go/ssl"); + } + + var crtFiles = RunCmd("find /usr/local/etc/trojan-go/ssl/*.crt").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + var keyFiles = RunCmd("find /usr/local/etc/trojan-go/ssl/*.key").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + if (crtFiles.Length > 0 && keyFiles.Length > 0) + { + RunCmd($"mv {crtFiles[0]} /usr/local/etc/trojan-go/ssl/trojan-go.crt"); + RunCmd($"mv {keyFiles[0]} /usr/local/etc/trojan-go/ssl/trojan-go.key"); + } + else + { + Progress.Step = "上传失败"; + Progress.Desc = "上传证书失败,缺少 .crt 和 .key 文件"; + return; + } + + Progress.Desc = "重启trojan-go服务"; + RunCmd("systemctl restart trojan-go"); + + Progress.Percentage = 100; + Progress.Desc = "上传证书完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void DoUploadWeb(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Step = "上传静态网站"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "创建网站目录"; + if (!FileExists("/usr/share/caddy")) + { + RunCmd("mkdir /usr/share/caddy"); + } + RunCmd("rm -rf /usr/share/caddy/*"); + Progress.Percentage = 40; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + 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"); + Progress.Percentage = 700; + } + + Progress.Desc = "上传Caddy配置文件"; + UploadCaddySettings(useCustomWeb: true); + Progress.Percentage = 90; + + Progress.Desc = "重启caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 100; + Progress.Desc = "上传静态网站成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void UploadCaddySettings(bool useCustomWeb = false) + { + var config = TrojanGoConfigBuilder.BuildCaddyConfig(Settings, 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"); + } + + private void InstallTrojanGo() + { + RunCmd(@"curl https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh yes | bash"); + var success = FileExists("/usr/local/bin/trojan-go"); + if (success == false) + { + throw new Exception("trojan-go 安装失败,请联系开发者!"); + } + + Progress.Desc = "设置Trojan-Go权限"; + RunCmd($"sed -i 's/User=nobody/User=root/g' /etc/systemd/system/trojan-go.service"); + RunCmd($"sed -i 's/CapabilityBoundingSet=/#CapabilityBoundingSet=/g' /etc/systemd/system/trojan-go.service"); + RunCmd($"sed -i 's/AmbientCapabilities=/#AmbientCapabilities=/g' /etc/systemd/system/trojan-go.service"); + RunCmd($"systemctl daemon-reload"); + + if (Settings.WithTLS) + { + Progress.Desc = "安装TLS证书"; + InstallCert( + dirPath: "/usr/local/etc/trojan-go/ssl", + certName: "trojan-go.crt", + keyName: "trojan-go.key"); + } + + Progress.Desc = "上传Trojan-Go配置文件"; + UploadTrojanGoSettings(); + } + + private void UploadTrojanGoSettings() + { + // 上传配置 + Progress.Desc = "生成配置文件"; + var settings = TrojanGoConfigBuilder.BuildTrojanGoConfig(Settings); + var stream = new MemoryStream(Encoding.UTF8.GetBytes(settings)); + + Progress.Desc = "正在上传配置文件"; + UploadFile(stream, "/usr/local/etc/trojan-go/config.json"); + + } + + #endregion + + + } +} diff --git a/ProxySuper.Core/Services/V2rayConfigBuilder.cs b/ProxySuper.Core/Services/V2rayConfigBuilder.cs new file mode 100644 index 0000000..585ca44 --- /dev/null +++ b/ProxySuper.Core/Services/V2rayConfigBuilder.cs @@ -0,0 +1,252 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using ProxySuper.Core.Models.Projects; +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 V2rayConfigBuilder + { + private const string ServerLogDir = @"Templates\v2ray\server\00_log"; + private const string ServerApiDir = @"Templates\v2ray\server\01_api"; + private const string ServerDnsDir = @"Templates\v2ray\server\02_dns"; + private const string ServerRoutingDir = @"Templates\v2ray\server\03_routing"; + private const string ServerPolicyDir = @"Templates\v2ray\server\04_policy"; + private const string ServerInboundsDir = @"Templates\v2ray\server\05_inbounds"; + private const string ServerOutboundsDir = @"Templates\v2ray\server\06_outbounds"; + private const string ServerTransportDir = @"Templates\v2ray\server\07_transport"; + private const string ServerStatsDir = @"Templates\v2ray\server\08_stats"; + private const string ServerReverseDir = @"Templates\v2ray\server\09_reverse"; + private const string CaddyFileDir = @"Templates\v2ray\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 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 LoadV2rayConfig() + { + 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(V2raySettings parameters, bool useCustomWeb = false) + { + var caddyStr = File.ReadAllText(Path.Combine(CaddyFileDir, "base.caddyfile")); + caddyStr = caddyStr.Replace("##domain##", parameters.IsIPAddress ? "" : 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; + } + + private static void SetClients(dynamic bound, List uuidList) + { + bound.settings.clients.Clear(); + uuidList.ForEach(id => + { + object obj; + + obj = new { id = id }; + + bound.settings.clients.Add(JToken.FromObject(obj)); + }); + } + + + public static string BuildV2rayConfig(V2raySettings parameters) + { + var uuidList = parameters.MulitUUID; + uuidList.Insert(0, parameters.UUID); + + var xrayConfig = LoadV2rayConfig(); + + var baseBound = GetBound("VLESS_TCP_TLS.json"); + baseBound.port = parameters.Port; + baseBound.settings.fallbacks.Add(JToken.FromObject(new + { + dest = FullbackPort + })); + xrayConfig.inbounds.Add(baseBound); + SetClients(baseBound, uuidList); + + #region Fullbacks + + if (parameters.Types.Contains(RayType.VLESS_WS)) + { + var wsInbound = GetBound("VLESS_WS.json"); + wsInbound.port = VLESS_WS_Port; + SetClients(wsInbound, uuidList); + 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(RayType.VMESS_TCP)) + { + var mtcpBound = GetBound("VMESS_TCP.json"); + mtcpBound.port = VMESS_TCP_Port; + SetClients(mtcpBound, uuidList); + 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(RayType.VMESS_WS)) + { + var mwsBound = GetBound("VMESS_WS.json"); + mwsBound.port = VMESS_WS_Port; + SetClients(mwsBound, uuidList); + 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(RayType.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)); + } + #endregion + + if (parameters.Types.Contains(RayType.VLESS_gRPC)) + { + var gRPCInBound = GetBound("VLESS_gRPC.json"); + gRPCInBound.port = parameters.VLESS_gRPC_Port; + SetClients(gRPCInBound, uuidList); + gRPCInBound.streamSettings.grpcSettings.serviceName = parameters.VLESS_gRPC_ServiceName; + gRPCInBound.streamSettings.tlsSettings.serverName = parameters.Domain; + xrayConfig.inbounds.Add(JToken.FromObject(gRPCInBound)); + } + + if (parameters.Types.Contains(RayType.VLESS_KCP)) + { + var kcpBound = GetBound("VLESS_KCP.json"); + kcpBound.port = parameters.VLESS_KCP_Port; + SetClients(kcpBound, uuidList); + 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(RayType.VMESS_KCP)) + { + var kcpBound = GetBound("VMESS_KCP.json"); + kcpBound.port = parameters.VMESS_KCP_Port; + SetClients(kcpBound, uuidList); + 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(RayType.ShadowsocksAEAD)) + { + var ssBound = GetBound("Shadowsocks-AEAD.json"); + ssBound.port = parameters.ShadowSocksPort; + ssBound.settings.password = parameters.ShadowSocksPassword; + ssBound.settings.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; + } + } +} diff --git a/ProxySuper.Core/Services/V2rayService.cs b/ProxySuper.Core/Services/V2rayService.cs new file mode 100644 index 0000000..98266d2 --- /dev/null +++ b/ProxySuper.Core/Services/V2rayService.cs @@ -0,0 +1,449 @@ +using Microsoft.Win32; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ProxySuper.Core.Services +{ + public class V2rayService : ServiceBase + { + public V2rayService(Host host, V2raySettings settings) : base(host, settings) + { + } + + public void Install() + { + Task.Factory.StartNew(() => + { + try + { + int index = 1; + EnsureRootUser(); + + if (FileExists("/usr/local/bin/v2ray")) + { + var btnResult = MessageBox.Show("已经安装v2ray,是否需要重装?", "提示", MessageBoxButton.YesNo); + if (btnResult == MessageBoxResult.No) + { + MessageBox.Show("安装终止", "提示"); + return; + } + } + + Progress.Step = $"{index++}. 检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 5; + + Progress.Step = $"{index++}. 安装必要的系统工具"; + InstallSystemTools(); + Progress.Percentage = 15; + + Progress.Step = $"{index++}. 配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 20; + + Progress.Step = $"{index++}. 检测网络环境"; + EnsureNetwork(); + if (Settings.IsIPAddress) + { + Progress.Desc = ("检查域名是否解析正确"); + ValidateDomain(); + } + Progress.Percentage = 25; + + Progress.Step = $"{index}. 同步系统和本地时间"; + SyncTimeDiff(); + Progress.Percentage = 30; + + Progress.Step = $"{index++}. 安装Caddy服务器"; + InstallCaddy(); + Progress.Percentage = 50; + + Progress.Step = $"{index++}. 安装V2ray-Core"; + InstallV2ray(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 上传Web服务器配置"; + UploadCaddyFile(); + Progress.Percentage = 90; + + Progress.Step = $"{index++}. 启动BBR"; + EnableBBR(); + + Progress.Desc = "重启V2ray服务"; + + RunCmd("systemctl restart caddy"); + RunCmd("systemctl restart v2ray"); + + Progress.Percentage = 100; + Progress.Step = "安装成功"; + Progress.Desc = string.Empty; + + if (!Settings.WithTLS) + { + Progress.Step = "安装成功,请上传您的 TLS 证书。"; + } + else + { + NavigationService.Navigate(Settings); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateSettings() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新V2ray配置"; + Progress.Percentage = 0; + EnsureRootUser(); + var index = 0; + + Progress.Desc = $"{index++}. 检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = $"{index++}. 配置防火墙"; + RunCmd("systemctl stop v2ray"); + RunCmd("systemctl stop caddy"); + ConfigFirewalld(); + Progress.Percentage = 40; + + Progress.Desc = $"{index++}. 上传V2ray配置文件"; + var configJson = V2rayConfigBuilder.BuildV2rayConfig(Settings); + WriteToFile(configJson, "/usr/local/etc/v2ray/config.json"); + Progress.Percentage = 70; + + Progress.Desc = $"{index++}. 上传Caddy配置文件"; + UploadCaddyFile(); + Progress.Percentage = 90; + + Progress.Desc = $"{index++}. 重启v2ray服务"; + RunCmd("systemctl restart caddy"); + RunCmd("systemctl restart v2ray"); + Progress.Percentage = 100; + + Progress.Desc = ("更新配置成功"); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateV2rayCore() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新V2ray-Core"; + Progress.Percentage = 0; + + EnsureRootUser(); + Progress.Percentage = 20; + + Progress.Desc = "下载最新版本V2ray-Core"; + EnsureSystemEnv(); + Progress.Percentage = 40; + + RunCmd("bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)"); + RunCmd("systemctl restart v2ray"); + Progress.Percentage = 100; + + Progress.Desc = "更新V2ray-Core成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + var index = 1; + Progress.Percentage = 0; + + Progress.Step = $"{index++}. 检测系统环境"; + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Step = $"{index++}. 卸载Caddy服务"; + UninstallCaddy(); + Progress.Percentage = 40; + + Progress.Step = $"{index++}. 卸载V2ray服务"; + UninstallV2ray(); + Progress.Percentage = 60; + + Progress.Step = $"{index++}. 卸载Acme证书申请服务"; + UninstallAcme(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 重置防火墙端口"; + ResetFirewalld(); + Progress.Percentage = 100; + + Progress.Step = "卸载完成"; + Progress.Desc = "卸载完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UploadCert() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadCert; + fileDialog.ShowDialog(); + } + + public void UploadWeb() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadWeb; + fileDialog.ShowDialog(); + } + + public void ApplyForCert() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Percentage = 0; + Progress.Step = "续签证书"; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + + Progress.Desc = "安装证书"; + InstallCert( + dirPath: "/usr/local/etc/v2ray/ssl", + certName: "v2ray_ssl.crt", + keyName: "v2ray_ssl.key"); + + Progress.Percentage = 90; + Progress.Desc = "重启服务"; + RunCmd("systemctl restart v2ray"); + + Progress.Percentage = 100; + Progress.Desc = "续签证书成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + + #region 似有方法 + + private void DoUploadCert(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Percentage = 0; + Progress.Step = "上传自有证书"; + Progress.Desc = "检测系统环境"; + + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + var oldFileName = $"ssl_{DateTime.Now.Ticks}"; + RunCmd($"mv /usr/local/etc/v2ray/ssl /usr/local/etc/v2ray/{oldFileName}"); + + RunCmd("mkdir /usr/local/etc/v2ray/ssl"); + UploadFile(stream, "/usr/local/etc/v2ray/ssl/ssl.zip"); + RunCmd("unzip /usr/local/etc/v2ray/ssl/ssl.zip -d /usr/local/etc/v2ray/ssl"); + } + + var crtFiles = RunCmd("find /usr/local/etc/v2ray/ssl/*.crt").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + var keyFiles = RunCmd("find /usr/local/etc/v2ray/ssl/*.key").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + if (crtFiles.Length > 0 && keyFiles.Length > 0) + { + RunCmd($"mv {crtFiles[0]} /usr/local/etc/v2ray/ssl/v2ray_ssl.crt"); + RunCmd($"mv {keyFiles[0]} /usr/local/etc/v2ray/ssl/v2ray_ssl.key"); + } + else + { + Progress.Step = "上传失败"; + Progress.Desc = "上传证书失败,缺少 .crt 和 .key 文件"; + return; + } + + Progress.Desc = "重启V2ray服务"; + RunCmd("systemctl restart v2ray"); + + Progress.Percentage = 100; + Progress.Desc = "上传证书完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void DoUploadWeb(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Step = "上传静态网站"; + Progress.Desc = "上传静态网站"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "创建网站目录"; + if (!FileExists("/usr/share/caddy")) + { + RunCmd("mkdir /usr/share/caddy"); + } + RunCmd("rm -rf /usr/share/caddy/*"); + Progress.Percentage = 40; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + 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"); + Progress.Percentage = 80; + + Progress.Desc = "上传Web配置文件"; + UploadCaddyFile(useCustomWeb: true); + Progress.Percentage = 90; + + Progress.Desc = "重启caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 100; + + Progress.Desc = "上传静态网站成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void InstallV2ray() + { + Progress.Desc = ("开始安装V2ray-Core"); + RunCmd("bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)"); + + if (!FileExists("/usr/local/bin/v2ray")) + { + Progress.Desc = ("V2ray-Core安装失败,请联系开发者"); + throw new Exception("V2ray-Core安装失败,请联系开发者"); + } + + Progress.Desc = ("设置V2ray-Core权限"); + RunCmd($"sed -i 's/User=nobody/User=root/g' /etc/systemd/system/v2ray.service"); + RunCmd($"sed -i 's/CapabilityBoundingSet=/#CapabilityBoundingSet=/g' /etc/systemd/system/v2ray.service"); + RunCmd($"sed -i 's/AmbientCapabilities=/#AmbientCapabilities=/g' /etc/systemd/system/v2ray.service"); + RunCmd($"systemctl daemon-reload"); + RunCmd("systemctl enable v2ray"); + + if (FileExists("/usr/local/etc/v2ray/config.json")) + { + RunCmd(@"mv /usr/local/etc/v2ray/config.json /usr/local/etc/v2ray/config.json.1"); + } + Progress.Percentage = 60; + + if (Settings.WithTLS && !Settings.IsIPAddress) + { + Progress.Desc = ("安装TLS证书"); + InstallCert( + dirPath: "/usr/local/etc/v2ray/ssl", + certName: "v2ray_ssl.crt", + keyName: "v2ray_ssl.key"); + Progress.Percentage = 75; + } + + Progress.Desc = ("生成v2ray服务器配置文件"); + var configJson = V2rayConfigBuilder.BuildV2rayConfig(Settings); + WriteToFile(configJson, "/usr/local/etc/v2ray/config.json"); + } + + private void UploadCaddyFile(bool useCustomWeb = false) + { + var configJson = V2rayConfigBuilder.BuildCaddyConfig(Settings, useCustomWeb); + + if (FileExists("/etc/caddy/Caddyfile")) + { + RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back"); + } + WriteToFile(configJson, "/etc/caddy/Caddyfile"); + } + + + private void UninstallV2ray() + { + Progress.Desc = "关闭V2ray服务"; + RunCmd("systemctl stop v2ray"); + RunCmd("systemctl disable v2ray"); + + Progress.Desc = "卸载V2ray"; + RunCmd("bash <(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh) --remove"); + } + + private void UninstallAcme() + { + Progress.Desc = "卸载 acme.sh"; + RunCmd("acme.sh --uninstall"); + + Progress.Desc = "删除 acme.sh 相关文件"; + RunCmd("rm -rf ~/.acme.sh"); + } + + #endregion + } +} diff --git a/ProxySuper.Core/Services/XrayConfigBuilder.cs b/ProxySuper.Core/Services/XrayConfigBuilder.cs index 12226bc..d93a1ba 100644 --- a/ProxySuper.Core/Services/XrayConfigBuilder.cs +++ b/ProxySuper.Core/Services/XrayConfigBuilder.cs @@ -129,7 +129,7 @@ namespace ProxySuper.Core.Services #region Fullbacks - if (parameters.Types.Contains(XrayType.VLESS_WS)) + if (parameters.Types.Contains(RayType.VLESS_WS)) { var wsInbound = GetBound("VLESS_WS.json"); wsInbound.port = VLESS_WS_Port; @@ -144,7 +144,7 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(wsInbound)); } - if (parameters.Types.Contains(XrayType.VMESS_TCP)) + if (parameters.Types.Contains(RayType.VMESS_TCP)) { var mtcpBound = GetBound("VMESS_TCP.json"); mtcpBound.port = VMESS_TCP_Port; @@ -159,7 +159,7 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(mtcpBound)); } - if (parameters.Types.Contains(XrayType.VMESS_WS)) + if (parameters.Types.Contains(RayType.VMESS_WS)) { var mwsBound = GetBound("VMESS_WS.json"); mwsBound.port = VMESS_WS_Port; @@ -174,7 +174,7 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(mwsBound)); } - if (parameters.Types.Contains(XrayType.Trojan_TCP)) + if (parameters.Types.Contains(RayType.Trojan_TCP)) { var trojanTcpBound = GetBound("Trojan_TCP.json"); trojanTcpBound.port = Trojan_TCP_Port; @@ -189,7 +189,7 @@ namespace ProxySuper.Core.Services } #endregion - if (parameters.Types.Contains(XrayType.VLESS_gRPC)) + if (parameters.Types.Contains(RayType.VLESS_gRPC)) { var gRPCInBound = GetBound("VLESS_gRPC.json"); gRPCInBound.port = parameters.VLESS_gRPC_Port; @@ -199,7 +199,7 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(gRPCInBound)); } - if (parameters.Types.Contains(XrayType.VLESS_KCP)) + if (parameters.Types.Contains(RayType.VLESS_KCP)) { var kcpBound = GetBound("VLESS_KCP.json"); kcpBound.port = parameters.VLESS_KCP_Port; @@ -209,7 +209,7 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(kcpBound)); } - if (parameters.Types.Contains(XrayType.VMESS_KCP)) + if (parameters.Types.Contains(RayType.VMESS_KCP)) { var kcpBound = GetBound("VMESS_KCP.json"); kcpBound.port = parameters.VMESS_KCP_Port; @@ -219,12 +219,12 @@ namespace ProxySuper.Core.Services xrayConfig.inbounds.Add(JToken.FromObject(kcpBound)); } - if (parameters.Types.Contains(XrayType.ShadowsocksAEAD)) + if (parameters.Types.Contains(RayType.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; + ssBound.settings.password = parameters.ShadowSocksPassword; + ssBound.settings.method = parameters.ShadowSocksMethod; xrayConfig.inbounds.Add(JToken.FromObject(ssBound)); } diff --git a/ProxySuper.Core/Services/XrayProject.cs b/ProxySuper.Core/Services/XrayProject.cs deleted file mode 100644 index 4dc8146..0000000 --- a/ProxySuper.Core/Services/XrayProject.cs +++ /dev/null @@ -1,329 +0,0 @@ -using Newtonsoft.Json; -using ProxySuper.Core.Models.Projects; -using Renci.SshNet; -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Windows; - -namespace ProxySuper.Core.Services -{ - public class XrayProject : ProjectBase - { - - 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 writeOutput) : base(sshClient, parameters, writeOutput) - { - } - - /// - /// 安装Xray - /// - 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("安装必要的系统工具..."); - ConfigureSoftware(); - WriteOutput("系统工具安装完成"); - - WriteOutput("配置防火墙..."); - ConfigFirewalld(); - WriteOutput("防火墙配置完成"); - - WriteOutput("检测网络环境"); - EnsureIP(); - WriteOutput("检测网络环境完成"); - - WriteOutput("同步系统和本地时间..."); - SyncTimeDiff(); - WriteOutput("时间同步完成"); - - if (!Parameters.IsIPAddress) - { - WriteOutput("检测域名是否绑定本机IP..."); - ValidateDomain(); - WriteOutput("域名检测完成"); - } - - WriteOutput("安装Caddy..."); - InstallCaddy(); - WriteOutput("Caddy安装完成"); - - WriteOutput("安装Xray-Core..."); - InstallXrayWithCert(); - WriteOutput("Xray-Core安装完成"); - - WriteOutput("启动BBR"); - EnableBBR(); - - UploadCaddyFile(); - WriteOutput("************"); - WriteOutput("安装完成,尽情享用吧......"); - WriteOutput("************"); - } - catch (Exception ex) - { - var errorLog = "安装终止," + ex.Message; - WriteOutput(errorLog); - MessageBox.Show("安装失败,请联系开发者或上传日志文件(Logs文件夹下)到github提问。"); - } - } - - public void UninstallProxy() - { - EnsureRootAuth(); - EnsureSystemEnv(); - WriteOutput("卸载Caddy"); - UninstallCaddy(); - WriteOutput("卸载Xray"); - UninstallXray(); - WriteOutput("卸载证书"); - UninstallAcme(); - WriteOutput("关闭端口"); - ResetFirewalld(); - - WriteOutput("************ 卸载完成 ************"); - } - - /// - /// 更新xray内核 - /// - 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内核完成 ************"); - } - - /// - /// 更新xray配置 - /// - public void UpdateXraySettings() - { - EnsureRootAuth(); - EnsureSystemEnv(); - - RunCmd("systemctl stop caddy"); - RunCmd("systemctl stop xray"); - - ConfigFirewalld(); - 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"); - - UploadCaddyFile(string.IsNullOrEmpty(Parameters.MaskDomain)); - RunCmd("systemctl restart xray"); - WriteOutput("************ 更新Xray配置成功,更新配置不包含域名,如果域名更换请重新安装。 ************"); - } - - /// - /// 重装Caddy - /// - public void DoUninstallCaddy() - { - EnsureRootAuth(); - EnsureSystemEnv(); - UninstallCaddy(); - WriteOutput("************ 卸载Caddy完成 ************"); - } - - /// - /// 安装证书 - /// - public void InstallCertToXray(bool restartXray = false) - { - EnsureRootAuth(); - EnsureSystemEnv(); - InstallCert( - dirPath: "/usr/local/etc/xray/ssl", - certName: "xray_ssl.crt", - keyName: "xray_ssl.key"); - - WriteOutput("************ 安装证书完成 ************"); - RunCmd("systemctl restart xray"); - } - - /// - /// 上传证书 - /// - /// - /// - 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("************ 上传证书完成 ************"); - } - - /// - /// 上传静态网站 - /// - /// - 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("************ 上传网站模板完成 ************"); - } - - /// - /// 上传Caddy文件 - /// - /// - private void UploadCaddyFile(bool useCustomWeb = false) - { - var configJson = XrayConfigBuilder.BuildCaddyConfig(Parameters, useCustomWeb); - - if (FileExists("/etc/caddy/Caddyfile")) - { - RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back"); - } - WriteToFile(configJson, "/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"); - } - - if (!Parameters.IsIPAddress) - { - WriteOutput("安装TLS证书"); - InstallCertToXray(); - WriteOutput("TLS证书安装完成"); - } - - var configJson = XrayConfigBuilder.BuildXrayConfig(Parameters); - WriteToFile(configJson, "/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; - } - - } -} diff --git a/ProxySuper.Core/Services/XrayService.cs b/ProxySuper.Core/Services/XrayService.cs index 68df0b5..dce2df3 100644 --- a/ProxySuper.Core/Services/XrayService.cs +++ b/ProxySuper.Core/Services/XrayService.cs @@ -1,8 +1,11 @@ -using ProxySuper.Core.Helpers; +using Microsoft.Win32; +using ProxySuper.Core.Helpers; using ProxySuper.Core.Models.Hosts; using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.ViewModels; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -19,61 +22,360 @@ namespace ProxySuper.Core.Services public void Install() { - Task.Run(() => + Task.Factory.StartNew(() => { - int index = 1; - if (!IsRootUser()) + try { - MessageBox.Show("ProxySU需要使用Root用户进行安装!"); - return; + int index = 1; + EnsureRootUser(); + + if (FileExists("/usr/local/bin/xray")) + { + var btnResult = MessageBox.Show("已经安装Xray,是否需要重装?", "提示", MessageBoxButton.YesNo); + if (btnResult == MessageBoxResult.No) + { + MessageBox.Show("安装终止", "提示"); + return; + } + } + + Progress.Step = $"{index++}. 检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 5; + + Progress.Step = $"{index++}. 安装必要的系统工具"; + InstallSystemTools(); + Progress.Percentage = 15; + + Progress.Step = $"{index++}. 配置防火墙"; + ConfigFirewalld(); + Progress.Percentage = 20; + + Progress.Step = $"{index++}. 检测网络环境"; + EnsureNetwork(); + if (Settings.IsIPAddress) + { + Progress.Desc = ("检查域名是否解析正确"); + ValidateDomain(); + } + Progress.Percentage = 25; + + Progress.Step = $"{index}. 同步系统和本地时间"; + SyncTimeDiff(); + Progress.Percentage = 30; + + Progress.Step = $"{index++}. 安装Caddy服务器"; + InstallCaddy(); + Progress.Percentage = 50; + + Progress.Step = $"{index++}. 安装Xray-Core"; + InstallXray(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 上传Web服务器配置"; + UploadCaddyFile(); + Progress.Percentage = 90; + + Progress.Step = $"{index++}. 启动BBR"; + EnableBBR(); + + Progress.Desc = "重启Xray服务"; + RunCmd("systemctl restart caddy"); + RunCmd("systemctl restart xray"); + + Progress.Percentage = 100; + Progress.Step = "安装成功"; + Progress.Desc = string.Empty; + + if (!Settings.WithTLS) + { + Progress.Step = "安装成功,请上传您的 TLS 证书。"; + } + else + { + NavigationService.Navigate(Settings); + } } - - Progress.Step = $"{index++}. 检测系统环境"; - EnsureSystemEnv(); - Progress.Percentage = 5; - - Progress.Step = $"{index++}. 安装必要的系统工具"; - InstallSystemTools(); - Progress.Percentage = 15; - - Progress.Step = $"{index++}. 配置防火墙"; - ConfigFirewalld(); - Progress.Percentage = 20; - - Progress.Step = $"{index++}. 检测网络环境"; - EnsureNetwork(); - if (Settings.IsIPAddress) + catch (Exception ex) { - Progress.Desc = ("检查域名是否解析正确"); - ValidateDomain(); + MessageBox.Show(ex.Message); } - Progress.Percentage = 25; - - Progress.Step = $"{index}. 同步系统和本地时间"; - SyncTimeDiff(); - Progress.Percentage = 30; - - Progress.Step = $"{index++}. 安装Caddy服务器"; - InstallCaddy(); - Progress.Percentage = 50; - - Progress.Step = $"{index++}. 安装Xray-Core"; - InstallXray(); - Progress.Percentage = 80; - - Progress.Step = $"{index++}. 上传Web服务器配置"; - UploadCaddyFile(); - Progress.Percentage = 90; - - Progress.Step = $"{index++}. 启动BBR"; - EnableBBR(); - Progress.Percentage = 100; - - Progress.Desc = ("!!!安装Xray完成!!!"); }); } - public void InstallXray() + public void UpdateSettings() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新Xray配置"; + Progress.Percentage = 0; + EnsureRootUser(); + var index = 0; + + Progress.Desc = $"{index++}. 检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = $"{index++}. 配置防火墙"; + RunCmd("systemctl stop xray"); + RunCmd("systemctl stop caddy"); + ConfigFirewalld(); + Progress.Percentage = 40; + + Progress.Desc = $"{index++}. 上传Xray配置文件"; + var configJson = XrayConfigBuilder.BuildXrayConfig(Settings); + WriteToFile(configJson, "/usr/local/etc/xray/config.json"); + Progress.Percentage = 70; + + Progress.Desc = $"{index++}. 上传Caddy配置文件"; + UploadCaddyFile(); + Progress.Percentage = 90; + + Progress.Desc = $"{index++}. 重启xray服务"; + RunCmd("systemctl restart caddy"); + RunCmd("systemctl restart xray"); + Progress.Percentage = 100; + + Progress.Desc = ("更新配置成功"); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UpdateXrayCore() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Step = "更新Xray-Core"; + Progress.Percentage = 0; + + EnsureRootUser(); + Progress.Percentage = 20; + + Progress.Desc = "下载最新版本Xray-Core"; + EnsureSystemEnv(); + Progress.Percentage = 40; + + RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ install"); + RunCmd("systemctl restart xray"); + Progress.Percentage = 100; + + Progress.Desc = "更新Xray-Core成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void Uninstall() + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + var index = 1; + Progress.Percentage = 0; + + Progress.Step = $"{index++}. 检测系统环境"; + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Step = $"{index++}. 卸载Caddy服务"; + UninstallCaddy(); + Progress.Percentage = 40; + + Progress.Step = $"{index++}. 卸载Xray服务"; + UninstallXray(); + Progress.Percentage = 60; + + Progress.Step = $"{index++}. 卸载Acme证书申请服务"; + UninstallAcme(); + Progress.Percentage = 80; + + Progress.Step = $"{index++}. 重置防火墙端口"; + ResetFirewalld(); + Progress.Percentage = 100; + + Progress.Step = "卸载完成"; + Progress.Desc = "卸载完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + public void UploadCert() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadCert; + fileDialog.ShowDialog(); + } + + public void UploadWeb() + { + var fileDialog = new OpenFileDialog(); + fileDialog.Filter = "压缩文件|*.zip"; + fileDialog.FileOk += DoUploadWeb; + fileDialog.ShowDialog(); + } + + public void ApplyForCert() + { + Task.Factory.StartNew(() => + { + try + { + Progress.Percentage = 0; + Progress.Step = "续签证书"; + + Progress.Desc = "检测系统环境"; + EnsureRootUser(); + EnsureSystemEnv(); + + Progress.Desc = "安装证书"; + InstallCert( + dirPath: "/usr/local/etc/xray/ssl", + certName: "xray_ssl.crt", + keyName: "xray_ssl.key"); + + Progress.Percentage = 90; + Progress.Desc = "重启服务"; + RunCmd("systemctl restart xray"); + + Progress.Percentage = 100; + Progress.Desc = "续签证书成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + + #region 似有方法 + + private void DoUploadCert(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Percentage = 0; + Progress.Step = "上传自有证书"; + Progress.Desc = "检测系统环境"; + + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + 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); + var keyFiles = RunCmd("find /usr/local/etc/xray/ssl/*.key").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + if (crtFiles.Length > 0 && keyFiles.Length > 0) + { + RunCmd($"mv {crtFiles[0]} /usr/local/etc/xray/ssl/xray_ssl.crt"); + RunCmd($"mv {keyFiles[0]} /usr/local/etc/xray/ssl/xray_ssl.key"); + } + else + { + Progress.Step = "上传失败"; + Progress.Desc = "上传证书失败,缺少 .crt 和 .key 文件"; + return; + } + + Progress.Desc = "重启Xray服务"; + RunCmd("systemctl restart xray"); + + Progress.Percentage = 100; + Progress.Desc = "上传证书完成"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void DoUploadWeb(object sender, CancelEventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + EnsureRootUser(); + + Progress.Step = "上传静态网站"; + Progress.Desc = "上传静态网站"; + Progress.Percentage = 0; + + Progress.Desc = "检测系统环境"; + EnsureSystemEnv(); + Progress.Percentage = 20; + + Progress.Desc = "创建网站目录"; + if (!FileExists("/usr/share/caddy")) + { + RunCmd("mkdir /usr/share/caddy"); + } + RunCmd("rm -rf /usr/share/caddy/*"); + Progress.Percentage = 40; + + Progress.Desc = "正在上传文件"; + var file = sender as OpenFileDialog; + using (var stream = file.OpenFile()) + { + 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"); + Progress.Percentage = 80; + + Progress.Desc = "上传Web配置文件"; + UploadCaddyFile(useCustomWeb: true); + Progress.Percentage = 90; + + Progress.Desc = "重启caddy服务"; + RunCmd("systemctl restart caddy"); + Progress.Percentage = 100; + + Progress.Desc = "上传静态网站成功"; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + }); + } + + private void InstallXray() { Progress.Desc = ("开始安装Xray-Core"); RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ install"); @@ -96,7 +398,7 @@ namespace ProxySuper.Core.Services } Progress.Percentage = 60; - if (!Settings.IsIPAddress) + if (Settings.WithTLS && !Settings.IsIPAddress) { Progress.Desc = ("安装TLS证书"); InstallCert( @@ -109,7 +411,6 @@ namespace ProxySuper.Core.Services Progress.Desc = ("生成Xray服务器配置文件"); var configJson = XrayConfigBuilder.BuildXrayConfig(Settings); WriteToFile(configJson, "/usr/local/etc/xray/config.json"); - RunCmd("systemctl restart xray"); } private void UploadCaddyFile(bool useCustomWeb = false) @@ -121,7 +422,28 @@ namespace ProxySuper.Core.Services RunCmd("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.back"); } WriteToFile(configJson, "/etc/caddy/Caddyfile"); - RunCmd("systemctl restart caddy"); } + + + private void UninstallXray() + { + Progress.Desc = "关闭Xray服务"; + RunCmd("systemctl stop xray"); + RunCmd("systemctl disable xray"); + + Progress.Desc = "卸载Xray"; + RunCmd("bash -c \"$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)\" @ remove"); + } + + private void UninstallAcme() + { + Progress.Desc = "卸载 acme.sh"; + RunCmd("acme.sh --uninstall"); + + Progress.Desc = "删除 acme.sh 相关文件"; + RunCmd("rm -rf ~/.acme.sh"); + } + + #endregion } } diff --git a/ProxySuper.Core/ViewModels/BrookEditorViewModel.cs b/ProxySuper.Core/ViewModels/BrookEditorViewModel.cs index 9960068..29ef9e5 100644 --- a/ProxySuper.Core/ViewModels/BrookEditorViewModel.cs +++ b/ProxySuper.Core/ViewModels/BrookEditorViewModel.cs @@ -67,6 +67,8 @@ namespace ProxySuper.Core.ViewModels public IMvxCommand SaveCommand => new MvxCommand(() => Save()); + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); + public override void Prepare(Record parameter) { var record = Utils.DeepClone(parameter); @@ -84,5 +86,17 @@ namespace ProxySuper.Core.ViewModels BrookSettings = Settings, }); } + + private void SaveAndInstall() + { + var record = new Record + { + Id = this.Id, + Host = this.Host, + BrookSettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } } } diff --git a/ProxySuper.Core/ViewModels/BrookInstallViewModel.cs b/ProxySuper.Core/ViewModels/BrookInstallViewModel.cs new file mode 100644 index 0000000..c3bc429 --- /dev/null +++ b/ProxySuper.Core/ViewModels/BrookInstallViewModel.cs @@ -0,0 +1,65 @@ +using MvvmCross.Commands; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class BrookInstallViewModel : MvxViewModel + { + Host _host; + + BrookSettings _settings; + + BrookService _service; + + public override void Prepare(Record parameter) + { + _host = parameter.Host; + _settings = parameter.BrookSettings; + } + + public override Task Initialize() + { + _service = new BrookService(_host, _settings); + _service.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); + _service.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); + _service.Connect(); + return base.Initialize(); + } + + public override void ViewDestroy(bool viewFinishing = true) + { + _service.Disconnect(); + this.SaveInstallLog(); + base.ViewDestroy(viewFinishing); + } + + public ProjectProgress Progress => _service.Progress; + + public string Logs => _service.Progress.Logs; + + public IMvxCommand InstallCommand => new MvxCommand(_service.Install); + + public IMvxCommand UninstallCommand => new MvxCommand(_service.Uninstall); + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = System.IO.Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".brook.txt"); + File.WriteAllText(fileName, Logs); + } + } +} diff --git a/ProxySuper.Core/ViewModels/BrookInstallerViewModel.cs b/ProxySuper.Core/ViewModels/BrookInstallerViewModel.cs deleted file mode 100644 index 10e4084..0000000 --- a/ProxySuper.Core/ViewModels/BrookInstallerViewModel.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MvvmCross.ViewModels; -using ProxySuper.Core.Models; -using ProxySuper.Core.Models.Hosts; -using ProxySuper.Core.Models.Projects; -using ProxySuper.Core.Services; - -namespace ProxySuper.Core.ViewModels -{ - public class BrookInstallerViewModel : MvxViewModel - { - - public Host Host { get; set; } - - public BrookSettings Settings { get; set; } - - public override void Prepare(Record parameter) - { - var record = Utils.DeepClone(parameter); - Host = record.Host; - Settings = record.BrookSettings; - } - - private bool _connected; - public bool Connected - { - get - { - return _connected; - } - set - { - _connected = value; - RaisePropertyChanged("Connected"); - } - } - - public string CommandText { get; set; } - } -} diff --git a/ProxySuper.Core/ViewModels/HomeViewModel.cs b/ProxySuper.Core/ViewModels/HomeViewModel.cs index c20cd2a..f01c7c5 100644 --- a/ProxySuper.Core/ViewModels/HomeViewModel.cs +++ b/ProxySuper.Core/ViewModels/HomeViewModel.cs @@ -56,14 +56,52 @@ namespace ProxySuper.Core.ViewModels File.WriteAllText("Data/Record.json", json); } + public void SortDone(string id) + { + var item = Records.Where(x => x.Id == id).FirstOrDefault(); + if (item == null) return; + + var index = Records.IndexOf(item); + if (index >= Records.Count - 1) return; + + Records.Remove(item); + Records.Insert(index + 1, item); + + RaisePropertyChanged("Records"); + SaveToJson(); + } + + public void SortUp(string id) + { + var item = Records.Where(x => x.Id == id).FirstOrDefault(); + if (item == null) return; + + var index = Records.IndexOf(item); + if (index <= 0) return; + + Records.Remove(item); + Records.Insert(index - 1, item); + + RaisePropertyChanged("Records"); + SaveToJson(); + } + public MvxObservableCollection Records { get; set; } + public IMvxCommand SortUpCommand => new MvxCommand(SortUp); + + public IMvxCommand SortDoneCommand => new MvxCommand(SortDone); + + public IMvxCommand AddV2rayCommand => new MvxAsyncCommand(AddV2rayRecord); + public IMvxCommand AddXrayCommand => new MvxAsyncCommand(AddXrayRecord); public IMvxCommand AddTrojanGoCommand => new MvxAsyncCommand(AddTrojanGoRecord); public IMvxCommand AddNaiveProxyCommand => new MvxAsyncCommand(AddNaiveProxyRecord); + public IMvxCommand AddMTProtoGoCommand => new MvxAsyncCommand(AddMTProtoGoRecord); + public IMvxCommand AddBrookCommand => new MvxAsyncCommand(AddBrookRecord); public IMvxCommand RemoveCommand => new MvxAsyncCommand(DeleteRecord); @@ -74,6 +112,20 @@ namespace ProxySuper.Core.ViewModels public IMvxCommand InstallCommand => new MvxAsyncCommand(GoToInstall); + public async Task AddV2rayRecord() + { + Record record = new Record(); + record.Id = Utils.GetTickID(); + record.Host = new Host(); + record.V2raySettings = new V2raySettings(); + + var result = await _navigationService.Navigate(record); + if (result == null) return; + + Records.Add(result); + SaveToJson(); + } + public async Task AddXrayRecord() { Record record = new Record(); @@ -103,6 +155,21 @@ namespace ProxySuper.Core.ViewModels SaveToJson(); } + public async Task AddMTProtoGoRecord() + { + Record record = new Record(); + record.Id = Utils.GetTickID(); + record.Host = new Host(); + record.MTProtoGoSettings = new MTProtoGoSettings(); + + var result = await _navigationService.Navigate(record); + if (result == null) return; + + Records.Add(result); + + SaveToJson(); + } + public async Task AddNaiveProxyRecord() { Record record = new Record(); @@ -140,6 +207,14 @@ namespace ProxySuper.Core.ViewModels if (record == null) return; Record result = null; + if (record.Type == ProjectType.V2ray) + { + result = await _navigationService.Navigate(record); + if (result == null) return; + + record.Host = result.Host; + record.V2raySettings = result.V2raySettings; + } if (record.Type == ProjectType.Xray) { result = await _navigationService.Navigate(record); @@ -172,6 +247,14 @@ namespace ProxySuper.Core.ViewModels record.Host = result.Host; record.BrookSettings = result.BrookSettings; } + if (record.Type == ProjectType.MTProtoGo) + { + result = await _navigationService.Navigate(record); + if (result == null) return; + + record.Host = result.Host; + record.MTProtoGoSettings = result.MTProtoGoSettings; + } SaveToJson(); } @@ -196,6 +279,10 @@ namespace ProxySuper.Core.ViewModels var record = Records.FirstOrDefault(x => x.Id == id); if (record == null) return; + if (record.Type == ProjectType.V2ray) + { + await _navigationService.Navigate(record.V2raySettings); + } if (record.Type == ProjectType.Xray) { await _navigationService.Navigate(record.XraySettings); @@ -212,29 +299,45 @@ namespace ProxySuper.Core.ViewModels { await _navigationService.Navigate(record.BrookSettings); } + if (record.Type == ProjectType.MTProtoGo) + { + await _navigationService.Navigate(record.MTProtoGoSettings); + } } public async Task GoToInstall(string id) { var record = Records.FirstOrDefault(x => x.Id == id); if (record == null) return; + record.OnSave = SaveToJson; + if (record.Type == ProjectType.V2ray) + { + await _navigationService.Navigate(record); + } if (record.Type == ProjectType.Xray) { await _navigationService.Navigate(record); } if (record.Type == ProjectType.TrojanGo) { - await _navigationService.Navigate(record); + await _navigationService.Navigate(record); } if (record.Type == ProjectType.NaiveProxy) { - await _navigationService.Navigate(record); + await _navigationService.Navigate(record); } if (record.Type == ProjectType.Brook) { - await _navigationService.Navigate(record); + await _navigationService.Navigate(record); } + if (record.Type == ProjectType.MTProtoGo) + { + await _navigationService.Navigate(record); + } + + SaveToJson(); } + } } diff --git a/ProxySuper.Core/ViewModels/MTProtoGoConfigViewModel.cs b/ProxySuper.Core/ViewModels/MTProtoGoConfigViewModel.cs new file mode 100644 index 0000000..a6058ca --- /dev/null +++ b/ProxySuper.Core/ViewModels/MTProtoGoConfigViewModel.cs @@ -0,0 +1,21 @@ +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Projects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class MTProtoGoConfigViewModel : MvxViewModel + { + public MTProtoGoSettings Settings { get; set; } + + public override void Prepare(MTProtoGoSettings parameter) + { + Settings = parameter; + } + } +} diff --git a/ProxySuper.Core/ViewModels/MTProtoGoEditorViewModel.cs b/ProxySuper.Core/ViewModels/MTProtoGoEditorViewModel.cs new file mode 100644 index 0000000..fa983bf --- /dev/null +++ b/ProxySuper.Core/ViewModels/MTProtoGoEditorViewModel.cs @@ -0,0 +1,66 @@ +using MvvmCross.Commands; +using MvvmCross.Navigation; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class MTProtoGoEditorViewModel : MvxViewModel + { + public MTProtoGoEditorViewModel(IMvxNavigationService navigationService) + { + NavigationService = navigationService; + } + + public IMvxNavigationService NavigationService { get; } + + public IMvxCommand SaveCommand => new MvxCommand(Save); + + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); + + public string Id { get; set; } + + public Host Host { get; set; } + + public MTProtoGoSettings Settings { get; set; } + + public override void Prepare(Record parameter) + { + var record = Utils.DeepClone(parameter); + + Id = record.Id; + Host = record.Host; + Settings = record.MTProtoGoSettings; + } + + private void Save() + { + NavigationService.Close(this, new Record + { + Id = this.Id, + Host = this.Host, + MTProtoGoSettings = Settings, + }); + } + + private void SaveAndInstall() + { + var record = new Record + { + Id = this.Id, + Host = this.Host, + MTProtoGoSettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } + } +} diff --git a/ProxySuper.Core/ViewModels/MTProtoGoInstallViewModel.cs b/ProxySuper.Core/ViewModels/MTProtoGoInstallViewModel.cs new file mode 100644 index 0000000..794d4f1 --- /dev/null +++ b/ProxySuper.Core/ViewModels/MTProtoGoInstallViewModel.cs @@ -0,0 +1,94 @@ +using MvvmCross.Commands; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class MTProtoGoInstallViewModel : MvxViewModel + { + Host _host; + + MTProtoGoSettings _settings; + + MTProtoGoService _mtproxyService; + + Action _onSave; + + public override void Prepare(Record parameter) + { + _host = parameter.Host; + _settings = parameter.MTProtoGoSettings; + _onSave = parameter.OnSave; + } + + public override Task Initialize() + { + _mtproxyService = new MTProtoGoService(_host, _settings); + _mtproxyService.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); + _mtproxyService.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); + _mtproxyService.Connect(); + return base.Initialize(); + } + + public override void ViewDestroy(bool viewFinishing = true) + { + _mtproxyService.Disconnect(); + this.SaveInstallLog(); + base.ViewDestroy(viewFinishing); + } + + public ProjectProgress Progress + { + get => _mtproxyService.Progress; + } + + public string Logs + { + get => _mtproxyService.Progress.Logs; + } + + + #region Command + + public IMvxCommand InstallCommand => new MvxCommand(() => + { + _mtproxyService.Install(); + + // 安装时生成的Secret需要保存 + _onSave(); + }); + + public IMvxCommand UpdateSettingsCommand => new MvxCommand(() => + { + _mtproxyService.UpdateSettings(); + + // 安装时生成的Secret需要保存 + _onSave(); + }); + + public IMvxCommand UninstallCommand => new MvxCommand(_mtproxyService.Uninstall); + + #endregion + + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = System.IO.Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".mtproxy-go.txt"); + File.WriteAllText(fileName, Logs); + } + } +} diff --git a/ProxySuper.Core/ViewModels/NaiveProxyEditorViewModel.cs b/ProxySuper.Core/ViewModels/NaiveProxyEditorViewModel.cs index 0dda929..cb131e4 100644 --- a/ProxySuper.Core/ViewModels/NaiveProxyEditorViewModel.cs +++ b/ProxySuper.Core/ViewModels/NaiveProxyEditorViewModel.cs @@ -35,6 +35,8 @@ namespace ProxySuper.Core.ViewModels public IMvxCommand SaveCommand => new MvxCommand(Save); + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); + private void Save() { NavigationService.Close(this, new Record @@ -44,5 +46,18 @@ namespace ProxySuper.Core.ViewModels NaiveProxySettings = Settings }); } + + + private void SaveAndInstall() + { + var record = new Record + { + Id = this.Id, + Host = this.Host, + NaiveProxySettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } } } diff --git a/ProxySuper.Core/ViewModels/NaiveProxyInstallViewModel.cs b/ProxySuper.Core/ViewModels/NaiveProxyInstallViewModel.cs new file mode 100644 index 0000000..2987076 --- /dev/null +++ b/ProxySuper.Core/ViewModels/NaiveProxyInstallViewModel.cs @@ -0,0 +1,75 @@ +using MvvmCross.Commands; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class NaiveProxyInstallViewModel : MvxViewModel + { + Host _host; + + NaiveProxySettings _settings; + + NaiveProxyService _service; + + public override void Prepare(Record parameter) + { + _host = parameter.Host; + _settings = parameter.NaiveProxySettings; + } + + public override Task Initialize() + { + _service = new NaiveProxyService(_host, _settings); + _service.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); + _service.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); + _service.Connect(); + return base.Initialize(); + } + + public override void ViewDestroy(bool viewFinishing = true) + { + _service.Disconnect(); + this.SaveInstallLog(); + base.ViewDestroy(viewFinishing); + } + + + public ProjectProgress Progress => _service.Progress; + + public string Logs => _service.Progress.Logs; + + + #region Commands + + public IMvxCommand InstallCommand => new MvxCommand(_service.Install); + + public IMvxCommand UpdateSettingsCommand => new MvxCommand(_service.UpdateSettings); + + public IMvxCommand UninstallCommand => new MvxCommand(_service.Uninstall); + + public IMvxCommand UploadWebCommand => new MvxCommand(_service.UploadWeb); + + #endregion + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = System.IO.Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".naiveproxy.txt"); + File.WriteAllText(fileName, Logs); + } + } +} diff --git a/ProxySuper.Core/ViewModels/NaiveProxyInstallerViewModel.cs b/ProxySuper.Core/ViewModels/NaiveProxyInstallerViewModel.cs deleted file mode 100644 index 35381cf..0000000 --- a/ProxySuper.Core/ViewModels/NaiveProxyInstallerViewModel.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MvvmCross.ViewModels; -using ProxySuper.Core.Models; -using ProxySuper.Core.Models.Hosts; -using ProxySuper.Core.Models.Projects; -using ProxySuper.Core.Services; - -namespace ProxySuper.Core.ViewModels -{ - public class NaiveProxyInstallerViewModel : MvxViewModel - { - public Host Host { get; set; } - - public NaiveProxySettings Settings { get; set; } - - public override void Prepare(Record parameter) - { - var record = Utils.DeepClone(parameter); - Host = record.Host; - Settings = record.NaiveProxySettings; - } - - private bool _connected; - public bool Connected - { - get - { - return _connected; - } - set - { - _connected = value; - RaisePropertyChanged("Connected"); - } - } - - public string CommandText { get; set; } - - } -} diff --git a/ProxySuper.Core/ViewModels/TrojanGoEditorViewModel.cs b/ProxySuper.Core/ViewModels/TrojanGoEditorViewModel.cs index 4e52497..737e9b0 100644 --- a/ProxySuper.Core/ViewModels/TrojanGoEditorViewModel.cs +++ b/ProxySuper.Core/ViewModels/TrojanGoEditorViewModel.cs @@ -19,6 +19,8 @@ namespace ProxySuper.Core.ViewModels public IMvxCommand SaveCommand => new MvxCommand(Save); + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); + public string Id { get; set; } public Host Host { get; set; } @@ -43,6 +45,18 @@ namespace ProxySuper.Core.ViewModels TrojanGoSettings = Settings, }); } + + private void SaveAndInstall() + { + var record = new Record + { + Id = this.Id, + Host = this.Host, + TrojanGoSettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } } diff --git a/ProxySuper.Core/ViewModels/TrojanGoInstallViewModel.cs b/ProxySuper.Core/ViewModels/TrojanGoInstallViewModel.cs new file mode 100644 index 0000000..e458295 --- /dev/null +++ b/ProxySuper.Core/ViewModels/TrojanGoInstallViewModel.cs @@ -0,0 +1,85 @@ +using MvvmCross.Commands; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class TrojanGoInstallViewModel : MvxViewModel + { + Host _host; + + TrojanGoSettings _settings; + + TrojanGoService _trojanGoService; + + public override void Prepare(Record parameter) + { + _host = parameter.Host; + _settings = parameter.TrojanGoSettings; + } + + public override Task Initialize() + { + _trojanGoService = new TrojanGoService(_host, _settings); + _trojanGoService.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); + _trojanGoService.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); + _trojanGoService.Connect(); + return base.Initialize(); + } + + public override void ViewDestroy(bool viewFinishing = true) + { + _trojanGoService.Disconnect(); + this.SaveInstallLog(); + base.ViewDestroy(viewFinishing); + } + + public ProjectProgress Progress + { + get => _trojanGoService.Progress; + } + + public string Logs + { + get => _trojanGoService.Progress.Logs; + } + + + #region Command + + public IMvxCommand InstallCommand => new MvxCommand(_trojanGoService.Install); + + public IMvxCommand UpdateSettingsCommand => new MvxCommand(_trojanGoService.UpdateSettings); + + public IMvxCommand UninstallCommand => new MvxCommand(_trojanGoService.Uninstall); + + public IMvxCommand UploadCertCommand => new MvxCommand(_trojanGoService.UploadCert); + + public IMvxCommand UploadWebCommand => new MvxCommand(_trojanGoService.UploadWeb); + + public IMvxCommand ApplyForCertCommand => new MvxCommand(_trojanGoService.ApplyForCert); + + #endregion + + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = System.IO.Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".trojan-go.txt"); + File.WriteAllText(fileName, Logs); + } + } +} diff --git a/ProxySuper.Core/ViewModels/TrojanGoInstallerViewModel.cs b/ProxySuper.Core/ViewModels/TrojanGoInstallerViewModel.cs deleted file mode 100644 index 41ee15a..0000000 --- a/ProxySuper.Core/ViewModels/TrojanGoInstallerViewModel.cs +++ /dev/null @@ -1,40 +0,0 @@ -using MvvmCross.ViewModels; -using ProxySuper.Core.Models; -using ProxySuper.Core.Models.Hosts; -using ProxySuper.Core.Models.Projects; -using ProxySuper.Core.Services; - -namespace ProxySuper.Core.ViewModels -{ - public class TrojanGoInstallerViewModel : MvxViewModel - { - public Host Host { get; set; } - - public TrojanGoSettings Settings { get; set; } - - public override void Prepare(Record parameter) - { - var record = Utils.DeepClone(parameter); - Host = record.Host; - Settings = record.TrojanGoSettings; - } - - private bool _connected; - public bool Connected - { - get - { - return _connected; - } - set - { - _connected = value; - RaisePropertyChanged("Connected"); - } - } - - public string CommandText { get; set; } - - - } -} diff --git a/ProxySuper.Core/ViewModels/V2rayConfigViewModel.cs b/ProxySuper.Core/ViewModels/V2rayConfigViewModel.cs new file mode 100644 index 0000000..f381366 --- /dev/null +++ b/ProxySuper.Core/ViewModels/V2rayConfigViewModel.cs @@ -0,0 +1,93 @@ +using MvvmCross.ViewModels; +using ProxySuper.Core.Models.Projects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class V2rayConfigViewModel : MvxViewModel + { + public V2raySettings Settings { get; set; } + + public override void Prepare(V2raySettings parameter) + { + Settings = parameter; + } + + + public bool Checked_VLESS_TCP + { + get + { + return Settings.Types.Contains(RayType.VLESS_TCP); + } + } + + public bool Checked_VLESS_WS + { + get + { + return Settings.Types.Contains(RayType.VLESS_WS); + } + } + + public bool Checked_VLESS_KCP + { + get + { + return Settings.Types.Contains(RayType.VLESS_KCP); + } + } + + public bool Checked_VLESS_gRPC + { + get + { + return Settings.Types.Contains(RayType.VLESS_gRPC); + } + } + + public bool Checked_VMESS_TCP + { + get + { + return Settings.Types.Contains(RayType.VMESS_TCP); + } + } + + public bool Checked_VMESS_WS + { + get + { + return Settings.Types.Contains(RayType.VMESS_WS); + } + } + + public bool Checked_VMESS_KCP + { + get + { + return Settings.Types.Contains(RayType.VMESS_KCP); + } + } + + public bool Checked_Trojan_TCP + { + get + { + return Settings.Types.Contains(RayType.Trojan_TCP); + } + } + + public bool CheckedShadowSocks + { + get + { + return Settings.Types.Contains(RayType.ShadowsocksAEAD); + } + } + } +} diff --git a/ProxySuper.Core/ViewModels/V2rayEditorViewModel.cs b/ProxySuper.Core/ViewModels/V2rayEditorViewModel.cs new file mode 100644 index 0000000..1460073 --- /dev/null +++ b/ProxySuper.Core/ViewModels/V2rayEditorViewModel.cs @@ -0,0 +1,442 @@ +using MvvmCross.Commands; +using MvvmCross.Navigation; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; + +namespace ProxySuper.Core.ViewModels +{ + public partial class V2rayEditorViewModel : MvxViewModel + { + public V2rayEditorViewModel(IMvxNavigationService navigationService) + { + NavigationService = navigationService; + } + + public string Id { get; set; } + + public Host Host { get; set; } + + public V2raySettings Settings { get; set; } + + public IMvxCommand SaveCommand => new MvxCommand(Save); + + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); + + public IMvxNavigationService NavigationService { get; } + + public override void Prepare(Record parameter) + { + var record = Utils.DeepClone(parameter); + Id = record.Id; + Host = record.Host; + Settings = record.V2raySettings; + } + + public void Save() + { + NavigationService.Close(this, new Record() + { + Id = Id, + Host = Host, + V2raySettings = Settings, + }); + } + + public void SaveAndInstall() + { + var record = new Record() + { + Id = Id, + Host = Host, + V2raySettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } + } + + + + + + public partial class V2rayEditorViewModel + { + public IMvxCommand RandomUuid => new MvxCommand(() => GetUuid()); + + public bool WithTLS + { + get => Settings.WithTLS; + set + { + Settings.WithTLS = value; + RaisePropertyChanged("Port"); + } + } + + public int Port + { + get => Settings.Port; + set + { + Settings.Port = value; + RaisePropertyChanged("Port"); + } + } + + public int VLESS_KCP_Port + { + get => Settings.VLESS_KCP_Port; + set + { + Settings.VLESS_KCP_Port = value; + RaisePropertyChanged("VLESS_KCP_Port"); + } + } + + public int VMESS_KCP_Port + { + get => Settings.VMESS_KCP_Port; + set + { + Settings.VMESS_KCP_Port = value; + RaisePropertyChanged("VMESS_KCP_Port"); + } + } + + public int ShadowSocksPort + { + get => Settings.ShadowSocksPort; + set + { + Settings.ShadowSocksPort = value; + RaisePropertyChanged("ShadowSocksPort"); + } + } + + + public string UUID + { + get => Settings.UUID; + set + { + Settings.UUID = value; + RaisePropertyChanged("UUID"); + } + } + + public string MultiUUID + { + get => string.Join(",", Settings.MulitUUID); + set + { + var input = value.Replace(',', ','); + var arr = input.Split(',').ToList(); + Settings.MulitUUID = arr; + RaisePropertyChanged("MultiUUID"); + } + } + + public string Domain + { + get => Settings.Domain; + set + { + Settings.Domain = value; + RaisePropertyChanged("Domain"); + } + } + + public string MaskDomain + { + get => Settings.MaskDomain; + set + { + Settings.MaskDomain = value; + RaisePropertyChanged("MaskDomain"); + } + } + + public string TrojanPassword + { + get => Settings.TrojanPassword; + set => Settings.TrojanPassword = value; + } + + public bool Checked_Trojan_TCP + { + get + { + return Settings.Types.Contains(RayType.Trojan_TCP); + } + set + { + if (value == true) + { + if (!Settings.Types.Contains(RayType.Trojan_TCP)) + Settings.Types.Add(RayType.Trojan_TCP); + } + else + { + Settings.Types.Remove(RayType.Trojan_TCP); + } + RaisePropertyChanged("Checked_Trojan_TCP"); + } + } + public string Trojan_TCP_ShareLink + { + get => ShareLink.Build(RayType.Trojan_TCP, Settings); + } + + private List _ssMethods = new List { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305" }; + public List ShadowSocksMethods => _ssMethods; + public bool CheckedShadowSocks + { + + get => Settings.Types.Contains(RayType.ShadowsocksAEAD); + set + { + CheckBoxChanged(value, RayType.ShadowsocksAEAD); + RaisePropertyChanged("CheckedShadowSocks"); + } + } + public string ShadowSocksPassword + { + get => Settings.ShadowSocksPassword; + set => Settings.ShadowSocksPassword = value; + } + public string ShadowSocksMethod + { + get => Settings.ShadowSocksMethod; + set + { + var namespaceStr = typeof(ComboBoxItem).FullName + ":"; + var trimValue = value.Replace(namespaceStr, ""); + trimValue = trimValue.Trim(); + Settings.ShadowSocksMethod = trimValue; + RaisePropertyChanged("ShadowSocksMethod"); + } + } + public string ShadowSocksShareLink + { + get => ShareLink.Build(RayType.ShadowsocksAEAD, Settings); + } + + + private void CheckBoxChanged(bool value, RayType type) + { + if (value == true) + { + if (!Settings.Types.Contains(type)) + { + Settings.Types.Add(type); + } + } + else + { + Settings.Types.RemoveAll(x => x == type); + } + } + + + + private void GetUuid() + { + UUID = Guid.NewGuid().ToString(); + RaisePropertyChanged("UUID"); + } + + } + + /// + /// VMESS + /// + public partial class V2rayEditorViewModel + { + // vmess tcp + public bool Checked_VMESS_TCP + { + get => Settings.Types.Contains(RayType.VMESS_TCP); + set + { + CheckBoxChanged(value, RayType.VMESS_TCP); + RaisePropertyChanged("Checked_VMESS_TCP"); + } + } + public string VMESS_TCP_Path + { + get => Settings.VMESS_TCP_Path; + set => Settings.VMESS_TCP_Path = value; + } + public string VMESS_TCP_ShareLink + { + get => ShareLink.Build(RayType.VMESS_TCP, Settings); + } + + // vmess ws + public bool Checked_VMESS_WS + { + get => Settings.Types.Contains(RayType.VMESS_WS); + set + { + CheckBoxChanged(value, RayType.VMESS_WS); + RaisePropertyChanged("Checked_VMESS_WS"); + } + } + public string VMESS_WS_Path + { + get => Settings.VMESS_WS_Path; + set => Settings.VMESS_WS_Path = value; + } + public string VMESS_WS_ShareLink + { + get => ShareLink.Build(RayType.VMESS_WS, Settings); + } + + // vmess kcp + public string VMESS_KCP_Seed + { + get => Settings.VMESS_KCP_Seed; + set => Settings.VMESS_KCP_Seed = value; + } + public string VMESS_KCP_Type + { + get => Settings.VMESS_KCP_Type; + set + { + var namespaceStr = typeof(ComboBoxItem).FullName + ":"; + var trimValue = value.Replace(namespaceStr, ""); + trimValue = trimValue.Trim(); + Settings.VMESS_KCP_Type = trimValue; + RaisePropertyChanged("VMESS_KCP_Type"); + } + } + public bool Checked_VMESS_KCP + { + get => Settings.Types.Contains(RayType.VMESS_KCP); + set + { + CheckBoxChanged(value, RayType.VMESS_KCP); + RaisePropertyChanged("Checked_VMESS_KCP"); + } + } + public string VMESS_KCP_ShareLink + { + get => ShareLink.Build(RayType.VMESS_KCP, Settings); + } + + + private List _kcpTypes = new List { "none", "srtp", "utp", "wechat-video", "dtls", "wireguard", }; + public List KcpTypes => _kcpTypes; + } + + /// + /// VLESS + /// + public partial class V2rayEditorViewModel + { + // vless tcp + public bool Checked_VLESS_TCP + { + get => Settings.Types.Contains(RayType.VLESS_TCP); + set + { + CheckBoxChanged(value, RayType.VLESS_TCP); + RaisePropertyChanged("Checked_VLESS_TCP"); + } + } + public string VLESS_TCP_ShareLink + { + get => ShareLink.Build(RayType.VLESS_TCP, Settings); + } + + + // vless ws + public string VLESS_WS_Path + { + get => Settings.VLESS_WS_Path; + set => Settings.VLESS_WS_Path = value; + } + public bool Checked_VLESS_WS + { + get + { + return Settings.Types.Contains(RayType.VLESS_WS); + } + set + { + CheckBoxChanged(value, RayType.VLESS_WS); + RaisePropertyChanged("Checked_VLESS_WS"); + } + } + public string VLESS_WS_ShareLink + { + get => ShareLink.Build(RayType.VLESS_WS, Settings); + } + + // vless kcp + public string VLESS_KCP_Seed + { + get => Settings.VLESS_KCP_Seed; + set => Settings.VLESS_KCP_Seed = value; + } + public string VLESS_KCP_Type + { + get => Settings.VLESS_KCP_Type; + set + { + var namespaceStr = typeof(ComboBoxItem).FullName + ":"; + var trimValue = value.Replace(namespaceStr, ""); + trimValue = trimValue.Trim(); + Settings.VLESS_KCP_Type = trimValue; + RaisePropertyChanged("VLESS_KCP_Type"); + } + } + public bool Checked_VLESS_KCP + { + get => Settings.Types.Contains(RayType.VLESS_KCP); + set + { + CheckBoxChanged(value, RayType.VLESS_KCP); + RaisePropertyChanged("Checked_VLESS_KCP"); + } + } + public string VLESS_KCP_ShareLink + { + get => ShareLink.Build(RayType.VLESS_KCP, Settings); + } + + // vless grpc + public string VLESS_gRPC_ServiceName + { + get => Settings.VLESS_gRPC_ServiceName; + set => Settings.VLESS_gRPC_ServiceName = value; + } + public int VLESS_gRPC_Port + { + get => Settings.VLESS_gRPC_Port; + set => Settings.VLESS_gRPC_Port = value; + } + public bool Checked_VLESS_gRPC + { + get => Settings.Types.Contains(RayType.VLESS_gRPC); + set + { + CheckBoxChanged(value, RayType.VLESS_gRPC); + RaisePropertyChanged("Checked_VLESS_gRPC"); + } + } + public string VLESS_gRPC_ShareLink + { + get => ShareLink.Build(RayType.VLESS_gRPC, Settings); + } + } +} diff --git a/ProxySuper.Core/ViewModels/V2rayInstallViewModel.cs b/ProxySuper.Core/ViewModels/V2rayInstallViewModel.cs new file mode 100644 index 0000000..0bfa7aa --- /dev/null +++ b/ProxySuper.Core/ViewModels/V2rayInstallViewModel.cs @@ -0,0 +1,88 @@ +using MvvmCross.Commands; +using MvvmCross.ViewModels; +using ProxySuper.Core.Models; +using ProxySuper.Core.Models.Hosts; +using ProxySuper.Core.Models.Projects; +using ProxySuper.Core.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProxySuper.Core.ViewModels +{ + public class V2rayInstallViewModel : MvxViewModel + { + Host _host; + + V2raySettings _settings; + + V2rayService _service; + + public override void ViewDestroy(bool viewFinishing = true) + { + _service.Disconnect(); + this.SaveInstallLog(); + base.ViewDestroy(viewFinishing); + } + + public override void Prepare(Record parameter) + { + this._host = parameter.Host; + this._settings = parameter.V2raySettings; + } + + public override Task Initialize() + { + _service = new V2rayService(_host, _settings); + _service.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); + _service.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); + _service.Connect(); + + return base.Initialize(); + } + + public ProjectProgress Progress + { + get => _service.Progress; + } + + public string Logs + { + get => _service.Progress.Logs; + } + + + + #region Command + + public IMvxCommand InstallCommand => new MvxCommand(_service.Install); + + public IMvxCommand UpdateSettingsCommand => new MvxCommand(_service.UpdateSettings); + + public IMvxCommand UpdateV2rayCoreCommand => new MvxCommand(_service.UpdateV2rayCore); + + public IMvxCommand UninstallCommand => new MvxCommand(_service.Uninstall); + + public IMvxCommand UploadCertCommand => new MvxCommand(_service.UploadCert); + + public IMvxCommand UploadWebCommand => new MvxCommand(_service.UploadWeb); + + public IMvxCommand ApplyForCertCommand => new MvxCommand(_service.ApplyForCert); + + #endregion + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".v2ray.txt"); + File.WriteAllText(fileName, Logs); + } + } +} diff --git a/ProxySuper.Core/ViewModels/XrayConfigViewModel.cs b/ProxySuper.Core/ViewModels/XrayConfigViewModel.cs index 5988329..57d19aa 100644 --- a/ProxySuper.Core/ViewModels/XrayConfigViewModel.cs +++ b/ProxySuper.Core/ViewModels/XrayConfigViewModel.cs @@ -17,7 +17,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_TCP_XTLS); + return Settings.Types.Contains(RayType.VLESS_TCP_XTLS); } } @@ -25,7 +25,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_TCP); + return Settings.Types.Contains(RayType.VLESS_TCP); } } @@ -33,7 +33,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_WS); + return Settings.Types.Contains(RayType.VLESS_WS); } } @@ -41,7 +41,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_KCP); + return Settings.Types.Contains(RayType.VLESS_KCP); } } @@ -49,7 +49,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_gRPC); + return Settings.Types.Contains(RayType.VLESS_gRPC); } } @@ -57,7 +57,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VMESS_TCP); + return Settings.Types.Contains(RayType.VMESS_TCP); } } @@ -65,7 +65,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VMESS_WS); + return Settings.Types.Contains(RayType.VMESS_WS); } } @@ -73,7 +73,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VMESS_KCP); + return Settings.Types.Contains(RayType.VMESS_KCP); } } @@ -81,7 +81,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.Trojan_TCP); + return Settings.Types.Contains(RayType.Trojan_TCP); } } @@ -89,7 +89,7 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.ShadowsocksAEAD); + return Settings.Types.Contains(RayType.ShadowsocksAEAD); } } } diff --git a/ProxySuper.Core/ViewModels/XrayEditorViewModel.cs b/ProxySuper.Core/ViewModels/XrayEditorViewModel.cs index f34b1a4..db613f7 100644 --- a/ProxySuper.Core/ViewModels/XrayEditorViewModel.cs +++ b/ProxySuper.Core/ViewModels/XrayEditorViewModel.cs @@ -26,7 +26,9 @@ namespace ProxySuper.Core.ViewModels public XraySettings Settings { get; set; } - public IMvxCommand SaveCommand => new MvxCommand(() => Save()); + public IMvxCommand SaveCommand => new MvxCommand(Save); + + public IMvxCommand SaveAndInstallCommand => new MvxCommand(SaveAndInstall); public IMvxNavigationService NavigationService { get; } @@ -47,12 +49,33 @@ namespace ProxySuper.Core.ViewModels XraySettings = Settings, }); } + + public void SaveAndInstall() + { + var record = new Record() + { + Id = Id, + Host = Host, + XraySettings = Settings, + }; + NavigationService.Close(this, record); + NavigationService.Navigate(record); + } } public partial class XrayEditorViewModel { public IMvxCommand RandomUuid => new MvxCommand(() => GetUuid()); + public bool WithTLS + { + get => Settings.WithTLS; + set + { + Settings.WithTLS = value; + RaisePropertyChanged("Port"); + } + } public int Port { @@ -147,25 +170,25 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.Trojan_TCP); + return Settings.Types.Contains(RayType.Trojan_TCP); } set { if (value == true) { - if (!Settings.Types.Contains(XrayType.Trojan_TCP)) - Settings.Types.Add(XrayType.Trojan_TCP); + if (!Settings.Types.Contains(RayType.Trojan_TCP)) + Settings.Types.Add(RayType.Trojan_TCP); } else { - Settings.Types.Remove(XrayType.Trojan_TCP); + Settings.Types.Remove(RayType.Trojan_TCP); } RaisePropertyChanged("Checked_Trojan_TCP"); } } public string Trojan_TCP_ShareLink { - get => ShareLink.Build(XrayType.Trojan_TCP, Settings); + get => ShareLink.Build(RayType.Trojan_TCP, Settings); } private List _ssMethods = new List { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305" }; @@ -173,10 +196,10 @@ namespace ProxySuper.Core.ViewModels public bool CheckedShadowSocks { - get => Settings.Types.Contains(XrayType.ShadowsocksAEAD); + get => Settings.Types.Contains(RayType.ShadowsocksAEAD); set { - CheckBoxChanged(value, XrayType.ShadowsocksAEAD); + CheckBoxChanged(value, RayType.ShadowsocksAEAD); RaisePropertyChanged("CheckedShadowSocks"); } } @@ -199,11 +222,11 @@ namespace ProxySuper.Core.ViewModels } public string ShadowSocksShareLink { - get => ShareLink.Build(XrayType.ShadowsocksAEAD, Settings); + get => ShareLink.Build(RayType.ShadowsocksAEAD, Settings); } - private void CheckBoxChanged(bool value, XrayType type) + private void CheckBoxChanged(bool value, RayType type) { if (value == true) { @@ -236,10 +259,10 @@ namespace ProxySuper.Core.ViewModels // vmess tcp public bool Checked_VMESS_TCP { - get => Settings.Types.Contains(XrayType.VMESS_TCP); + get => Settings.Types.Contains(RayType.VMESS_TCP); set { - CheckBoxChanged(value, XrayType.VMESS_TCP); + CheckBoxChanged(value, RayType.VMESS_TCP); RaisePropertyChanged("Checked_VMESS_TCP"); } } @@ -250,16 +273,16 @@ namespace ProxySuper.Core.ViewModels } public string VMESS_TCP_ShareLink { - get => ShareLink.Build(XrayType.VMESS_TCP, Settings); + get => ShareLink.Build(RayType.VMESS_TCP, Settings); } // vmess ws public bool Checked_VMESS_WS { - get => Settings.Types.Contains(XrayType.VMESS_WS); + get => Settings.Types.Contains(RayType.VMESS_WS); set { - CheckBoxChanged(value, XrayType.VMESS_WS); + CheckBoxChanged(value, RayType.VMESS_WS); RaisePropertyChanged("Checked_VMESS_WS"); } } @@ -270,7 +293,7 @@ namespace ProxySuper.Core.ViewModels } public string VMESS_WS_ShareLink { - get => ShareLink.Build(XrayType.VMESS_WS, Settings); + get => ShareLink.Build(RayType.VMESS_WS, Settings); } // vmess kcp @@ -293,16 +316,16 @@ namespace ProxySuper.Core.ViewModels } public bool Checked_VMESS_KCP { - get => Settings.Types.Contains(XrayType.VMESS_KCP); + get => Settings.Types.Contains(RayType.VMESS_KCP); set { - CheckBoxChanged(value, XrayType.VMESS_KCP); + CheckBoxChanged(value, RayType.VMESS_KCP); RaisePropertyChanged("Checked_VMESS_KCP"); } } public string VMESS_KCP_ShareLink { - get => ShareLink.Build(XrayType.VMESS_KCP, Settings); + get => ShareLink.Build(RayType.VMESS_KCP, Settings); } @@ -319,31 +342,31 @@ namespace ProxySuper.Core.ViewModels // vless xtls public bool Checked_VLESS_TCP_XTLS { - get => Settings.Types.Contains(XrayType.VLESS_TCP_XTLS); + get => Settings.Types.Contains(RayType.VLESS_TCP_XTLS); set { - CheckBoxChanged(value, XrayType.VLESS_TCP_XTLS); + CheckBoxChanged(value, RayType.VLESS_TCP_XTLS); RaisePropertyChanged("Checked_VLESS_TCP_XTLS"); } } public string VLESS_TCP_XTLS_ShareLink { - get => ShareLink.Build(XrayType.VLESS_TCP_XTLS, Settings); + get => ShareLink.Build(RayType.VLESS_TCP_XTLS, Settings); } // vless tcp public bool Checked_VLESS_TCP { - get => Settings.Types.Contains(XrayType.VLESS_TCP); + get => Settings.Types.Contains(RayType.VLESS_TCP); set { - CheckBoxChanged(value, XrayType.VLESS_TCP); + CheckBoxChanged(value, RayType.VLESS_TCP); RaisePropertyChanged("Checked_VLESS_TCP"); } } public string VLESS_TCP_ShareLink { - get => ShareLink.Build(XrayType.VLESS_TCP, Settings); + get => ShareLink.Build(RayType.VLESS_TCP, Settings); } @@ -357,17 +380,17 @@ namespace ProxySuper.Core.ViewModels { get { - return Settings.Types.Contains(XrayType.VLESS_WS); + return Settings.Types.Contains(RayType.VLESS_WS); } set { - CheckBoxChanged(value, XrayType.VLESS_WS); + CheckBoxChanged(value, RayType.VLESS_WS); RaisePropertyChanged("Checked_VLESS_WS"); } } public string VLESS_WS_ShareLink { - get => ShareLink.Build(XrayType.VLESS_WS, Settings); + get => ShareLink.Build(RayType.VLESS_WS, Settings); } // vless kcp @@ -390,16 +413,16 @@ namespace ProxySuper.Core.ViewModels } public bool Checked_VLESS_KCP { - get => Settings.Types.Contains(XrayType.VLESS_KCP); + get => Settings.Types.Contains(RayType.VLESS_KCP); set { - CheckBoxChanged(value, XrayType.VLESS_KCP); + CheckBoxChanged(value, RayType.VLESS_KCP); RaisePropertyChanged("Checked_VLESS_KCP"); } } public string VLESS_KCP_ShareLink { - get => ShareLink.Build(XrayType.VLESS_KCP, Settings); + get => ShareLink.Build(RayType.VLESS_KCP, Settings); } // vless grpc @@ -415,16 +438,16 @@ namespace ProxySuper.Core.ViewModels } public bool Checked_VLESS_gRPC { - get => Settings.Types.Contains(XrayType.VLESS_gRPC); + get => Settings.Types.Contains(RayType.VLESS_gRPC); set { - CheckBoxChanged(value, XrayType.VLESS_gRPC); + CheckBoxChanged(value, RayType.VLESS_gRPC); RaisePropertyChanged("Checked_VLESS_gRPC"); } } public string VLESS_gRPC_ShareLink { - get => ShareLink.Build(XrayType.VLESS_gRPC, Settings); + get => ShareLink.Build(RayType.VLESS_gRPC, Settings); } } diff --git a/ProxySuper.Core/ViewModels/XrayInstallViewModel.cs b/ProxySuper.Core/ViewModels/XrayInstallViewModel.cs index 69ea300..f7d483e 100644 --- a/ProxySuper.Core/ViewModels/XrayInstallViewModel.cs +++ b/ProxySuper.Core/ViewModels/XrayInstallViewModel.cs @@ -6,6 +6,7 @@ using ProxySuper.Core.Models.Projects; using ProxySuper.Core.Services; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -20,11 +21,10 @@ namespace ProxySuper.Core.ViewModels XrayService _xrayService; - MvxInteraction _refreshLogInteraction = new MvxInteraction(); - public override void ViewDestroy(bool viewFinishing = true) { _xrayService.Disconnect(); + this.SaveInstallLog(); base.ViewDestroy(viewFinishing); } @@ -38,11 +38,7 @@ namespace ProxySuper.Core.ViewModels { _xrayService = new XrayService(_host, _settings); _xrayService.Progress.StepUpdate = () => RaisePropertyChanged("Progress"); - _xrayService.Progress.LogsUpdate = () => - { - RaisePropertyChanged("Logs"); - _refreshLogInteraction.Raise(); - }; + _xrayService.Progress.LogsUpdate = () => RaisePropertyChanged("Logs"); _xrayService.Connect(); return base.Initialize(); @@ -58,11 +54,35 @@ namespace ProxySuper.Core.ViewModels get => _xrayService.Progress.Logs; } - public IMvxInteraction LogsInteraction - { - get => _refreshLogInteraction; - } + + + #region Command public IMvxCommand InstallCommand => new MvxCommand(_xrayService.Install); + + public IMvxCommand UpdateSettingsCommand => new MvxCommand(_xrayService.UpdateSettings); + + public IMvxCommand UpdateXrayCoreCommand => new MvxCommand(_xrayService.UpdateXrayCore); + + public IMvxCommand UninstallCommand => new MvxCommand(_xrayService.Uninstall); + + public IMvxCommand UploadCertCommand => new MvxCommand(_xrayService.UploadCert); + + public IMvxCommand UploadWebCommand => new MvxCommand(_xrayService.UploadWeb); + + public IMvxCommand ApplyForCertCommand => new MvxCommand(_xrayService.ApplyForCert); + + #endregion + + private void SaveInstallLog() + { + if (!Directory.Exists("Logs")) + { + Directory.CreateDirectory("Logs"); + } + + var fileName = Path.Combine("Logs", DateTime.Now.ToString("yyyy-MM-dd hh-mm") + ".xary.txt"); + File.WriteAllText(fileName, Logs); + } } } diff --git a/ProxySuper.Core/ViewModels/XrayInstallerViewModel.cs b/ProxySuper.Core/ViewModels/XrayInstallerViewModel.cs deleted file mode 100644 index 48597cd..0000000 --- a/ProxySuper.Core/ViewModels/XrayInstallerViewModel.cs +++ /dev/null @@ -1,40 +0,0 @@ -using MvvmCross.ViewModels; -using ProxySuper.Core.Models; -using ProxySuper.Core.Models.Hosts; -using ProxySuper.Core.Models.Projects; -using ProxySuper.Core.Services; - -namespace ProxySuper.Core.ViewModels -{ - public class XrayInstallerViewModel : MvxViewModel - { - - public Host Host { get; set; } - - public XraySettings Settings { get; set; } - - public override void Prepare(Record parameter) - { - var record = Utils.DeepClone(parameter); - Host = record.Host; - Settings = record.XraySettings; - } - - - private bool _connected; - public bool Connected - { - get - { - return _connected; - } - set - { - _connected = value; - RaisePropertyChanged("Connected"); - } - } - - public string CommandText { get; set; } - } -} diff --git a/ProxySuper.WPF/Controls/ProgressControl.xaml b/ProxySuper.WPF/Controls/ProgressControl.xaml index a00c760..b45c461 100644 --- a/ProxySuper.WPF/Controls/ProgressControl.xaml +++ b/ProxySuper.WPF/Controls/ProgressControl.xaml @@ -19,7 +19,7 @@ VerticalScrollBarVisibility="Auto" Text="{Binding Path=Logs,Mode=OneWay}" VerticalContentAlignment="Top" - Padding="10" + Padding="10,0" FontSize="13" IsReadOnly="True" FontFamily="微软雅黑" diff --git a/ProxySuper.WPF/Controls/V2raySettingsControl.xaml b/ProxySuper.WPF/Controls/V2raySettingsControl.xaml new file mode 100644 index 0000000..5c63f27 --- /dev/null +++ b/ProxySuper.WPF/Controls/V2raySettingsControl.xaml @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +