diff --git a/Netch/Resources/zh-CN b/Netch/Resources/zh-CN
index 74a8f552..90ba5ceb 100644
--- a/Netch/Resources/zh-CN
+++ b/Netch/Resources/zh-CN
@@ -47,6 +47,7 @@
"Address": "地址",
"Username": "用户名",
+ "User": "用户",
"Password": "密码",
"Version": "版本",
"User ID": "用户 ID",
@@ -71,7 +72,7 @@
"Plugin Options": "插件参数",
"Remote Address": "远端地址",
"Local Addresses": "本地地址(可多个)",
- "Public Key": "节点公钥",
+ "Public Key": "公钥",
"Private Key": "私钥",
"PSK": "节点预共享密钥",
diff --git a/Netch/Servers/SSH/SSHForm.cs b/Netch/Servers/SSH/SSHForm.cs
new file mode 100644
index 00000000..928d3826
--- /dev/null
+++ b/Netch/Servers/SSH/SSHForm.cs
@@ -0,0 +1,19 @@
+using Netch.Forms;
+
+namespace Netch.Servers;
+
+[Fody.ConfigureAwait(true)]
+public class SSHForm : ServerForm
+{
+ public SSHForm(SSHServer? server = default)
+ {
+ server ??= new SSHServer();
+ Server = server;
+ CreateTextBox("User", "User", s => true, s => server.User = s, server.User);
+ CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
+ CreateTextBox("PrivateKey", "Private Key", s => true, s => server.PrivateKey = s, server.PrivateKey);
+ CreateTextBox("PublicKey", "Public Key", s => true, s => server.PublicKey = s, server.PublicKey);
+ }
+
+ protected override string TypeName { get; } = "SSH";
+}
\ No newline at end of file
diff --git a/Netch/Servers/SSH/SSHServer.cs b/Netch/Servers/SSH/SSHServer.cs
new file mode 100644
index 00000000..404f14fb
--- /dev/null
+++ b/Netch/Servers/SSH/SSHServer.cs
@@ -0,0 +1,33 @@
+using Netch.Models;
+
+namespace Netch.Servers;
+
+public class SSHServer : Server
+{
+ public override string Type { get; } = "SSH";
+
+ public override string MaskedData()
+ {
+ return $"{User}";
+ }
+
+ ///
+ /// 用户
+ ///
+ public string User { get; set; } = "root";
+
+ ///
+ /// 密码
+ ///
+ public string Password { get; set; } = string.Empty;
+
+ ///
+ /// 私钥
+ ///
+ public string PrivateKey { get; set; }
+
+ ///
+ /// 主机公钥
+ ///
+ public string? PublicKey { get; set; }
+}
diff --git a/Netch/Servers/SSH/SSHUtil.cs b/Netch/Servers/SSH/SSHUtil.cs
new file mode 100644
index 00000000..166b0def
--- /dev/null
+++ b/Netch/Servers/SSH/SSHUtil.cs
@@ -0,0 +1,53 @@
+using System.Text.Encodings.Web;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Netch.Interfaces;
+using Netch.Models;
+using Netch.Utils;
+
+namespace Netch.Servers;
+
+public class SSHUtil : IServerUtil
+{
+ public ushort Priority { get; } = 4;
+
+ public string TypeName { get; } = "SSH";
+
+ public string FullName { get; } = "SSH";
+
+ public string ShortName { get; } = "SSH";
+
+ public string[] UriScheme { get; } = { "ssh" };
+
+ public Type ServerType { get; } = typeof(SSHServer);
+
+ public void Edit(Server s)
+ {
+ new SSHForm((SSHServer)s).ShowDialog();
+ }
+
+ public void Create()
+ {
+ new SSHForm().ShowDialog();
+ }
+
+ public string GetShareLink(Server s)
+ {
+ return V2rayUtils.GetVShareLink(s, "ssh");
+ }
+
+ public IServerController GetController()
+ {
+ return new V2rayController();
+ }
+
+ public IEnumerable ParseUri(string text)
+ {
+ return V2rayUtils.ParseVUri(text);
+ }
+
+ public bool CheckServer(Server s)
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Netch/Servers/V2ray/V2rayConfig.cs b/Netch/Servers/V2ray/V2rayConfig.cs
index 2d26668e..d1db9e04 100644
--- a/Netch/Servers/V2ray/V2rayConfig.cs
+++ b/Netch/Servers/V2ray/V2rayConfig.cs
@@ -44,8 +44,12 @@ public class OutboundConfiguration
public string address { get; set; }
+ public string user { get; set; }
+
public ushort port { get; set; }
+ public string password { get; set; }
+
public string packetEncoding { get; set; }
public string plugin { get; set; }
@@ -58,6 +62,8 @@ public class OutboundConfiguration
public string peerPublicKey { get; set; }
+ public string publicKey { get; set; }
+
public string privateKey { get; set; }
public string preSharedKey { get; set; }
diff --git a/Netch/Servers/V2ray/V2rayConfigUtils.cs b/Netch/Servers/V2ray/V2rayConfigUtils.cs
index 94010b8e..5307e6de 100644
--- a/Netch/Servers/V2ray/V2rayConfigUtils.cs
+++ b/Netch/Servers/V2ray/V2rayConfigUtils.cs
@@ -145,21 +145,18 @@ public static class V2rayConfigUtils
}
case ShadowsocksServer ss:
outbound.protocol = "shadowsocks";
- outbound.settings = new OutboundConfiguration
+ outbound.settings.servers = new[]
{
- servers = new[]
+ new ShadowsocksServerItem
{
- new ShadowsocksServerItem
- {
- address = await server.AutoResolveHostnameAsync(),
- port = server.Port,
- method = ss.EncryptMethod,
- password = ss.Password,
- }
- },
- plugin = ss.Plugin ?? "",
- pluginOpts = ss.PluginOption ?? ""
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = ss.EncryptMethod,
+ password = ss.Password
+ }
};
+ outbound.settings.plugin = ss.Plugin ?? "";
+ outbound.settings.pluginOpts = ss.PluginOption ?? "";
if (Global.Settings.V2RayConfig.TCPFastOpen)
{
@@ -174,27 +171,24 @@ public static class V2rayConfigUtils
break;
case ShadowsocksRServer ssr:
outbound.protocol = "shadowsocks";
- outbound.settings = new OutboundConfiguration
+ outbound.settings.servers = new[]
{
- servers = new[]
+ new ShadowsocksServerItem
{
- new ShadowsocksServerItem
- {
- address = await server.AutoResolveHostnameAsync(),
- port = server.Port,
- method = ssr.EncryptMethod,
- password = ssr.Password,
- }
- },
- plugin = "shadowsocksr",
- pluginArgs = new string[]
- {
- "--obfs=" + ssr.OBFS,
- "--obfs-param=" + ssr.OBFSParam ?? "",
- "--protocol=" + ssr.Protocol,
- "--protocol-param=" + ssr.ProtocolParam ?? ""
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = ssr.EncryptMethod,
+ password = ssr.Password,
}
};
+ outbound.settings.plugin = "shadowsocksr";
+ outbound.settings.pluginArgs = new string[]
+ {
+ "--obfs=" + ssr.OBFS,
+ "--obfs-param=" + ssr.OBFSParam ?? "",
+ "--protocol=" + ssr.Protocol,
+ "--protocol-param=" + ssr.ProtocolParam ?? ""
+ };
if (Global.Settings.V2RayConfig.TCPFastOpen)
{
@@ -209,18 +203,15 @@ public static class V2rayConfigUtils
break;
case TrojanServer trojan:
outbound.protocol = "trojan";
- outbound.settings = new OutboundConfiguration
+ outbound.settings.servers = new[]
{
- servers = new[]
+ new ShadowsocksServerItem // I'm not serious
{
- new ShadowsocksServerItem // I'm not serious
- {
- address = await server.AutoResolveHostnameAsync(),
- port = server.Port,
- method = "",
- password = trojan.Password,
- flow = trojan.TLSSecureType == "xtls" ? "xtls-rprx-direct" : ""
- }
+ address = await server.AutoResolveHostnameAsync(),
+ port = server.Port,
+ method = "",
+ password = trojan.Password,
+ flow = trojan.TLSSecureType == "xtls" ? "xtls-rprx-direct" : ""
}
};
@@ -258,16 +249,13 @@ public static class V2rayConfigUtils
break;
case WireGuardServer wg:
outbound.protocol = "wireguard";
- outbound.settings = new OutboundConfiguration
- {
- address = await server.AutoResolveHostnameAsync(),
- port = server.Port,
- localAddresses = wg.LocalAddresses.SplitOrDefault(),
- peerPublicKey = wg.PeerPublicKey,
- privateKey = wg.PrivateKey,
- preSharedKey = wg.PreSharedKey,
- mtu = wg.MTU
- };
+ outbound.settings.address = await server.AutoResolveHostnameAsync();
+ outbound.settings.port = server.Port;
+ outbound.settings.localAddresses = wg.LocalAddresses.SplitOrDefault();
+ outbound.settings.peerPublicKey = wg.PeerPublicKey;
+ outbound.settings.privateKey = wg.PrivateKey;
+ outbound.settings.preSharedKey = wg.PreSharedKey;
+ outbound.settings.mtu = wg.MTU;
if (Global.Settings.V2RayConfig.TCPFastOpen)
{
@@ -281,6 +269,26 @@ public static class V2rayConfigUtils
}
break;
+ case SSHServer ssh:
+ outbound.protocol = "ssh";
+ outbound.settings.address = await server.AutoResolveHostnameAsync();
+ outbound.settings.port = server.Port;
+ outbound.settings.user = ssh.User;
+ outbound.settings.password = ssh.Password;
+ outbound.settings.privateKey = ssh.PrivateKey;
+ outbound.settings.publicKey = ssh.PublicKey;
+
+ if (Global.Settings.V2RayConfig.TCPFastOpen)
+ {
+ outbound.streamSettings = new StreamSettings
+ {
+ sockopt = new Sockopt
+ {
+ tcpFastOpen = true
+ }
+ };
+ }
+ break;
}
return outbound;