From d91026dc4fbfe5fedc4ee8e43dc0d08f1cf88356 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 29 Sep 2024 11:50:59 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=B8=8A=E4=BC=A0=E5=88=B0=E4=B8=BB?= =?UTF-8?q?=E6=9C=BA=EF=BC=8C=E6=94=AF=E6=8C=81socks=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-server/package.json | 2 + .../pipeline/service/access-service.ts | 2 +- .../plugins/plugin-host/access/ssh-access.ts | 13 +++++- .../src/plugins/plugin-host/lib/ssh.ts | 42 ++++++++++++++++++- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 309ffa84..0293a12c 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -70,6 +70,8 @@ "querystring": "^0.2.1", "reflect-metadata": "^0.1.13", "rimraf": "^5.0.5", + "socks": "^2.8.3", + "socks-proxy-agent": "^8.0.4", "ssh2": "^1.15.0", "strip-ansi": "^7.1.0", "svg-captcha": "^1.4.0", diff --git a/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts index 64df6e37..36ba8060 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts @@ -60,7 +60,7 @@ export class AccessService extends BaseService implements IAccessS const value = json[key]; const accessInputDefine = accessDefine.input[key]; if (!accessInputDefine) { - throw new ValidateException(`授权类型${accessType}不存在字段${key}`); + continue; } if (!accessInputDefine.encrypt || !value || typeof value !== 'string') { //定义无需加密、value为空、不是字符串 这些不需要加密 diff --git a/packages/ui/certd-server/src/plugins/plugin-host/access/ssh-access.ts b/packages/ui/certd-server/src/plugins/plugin-host/access/ssh-access.ts index e5bad29a..b490acb5 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/access/ssh-access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/access/ssh-access.ts @@ -18,7 +18,7 @@ export class SshAccess implements IAccess, ConnectConfig { host!: string; @AccessInput({ title: '端口', - value: '22', + value: 22, component: { name: 'a-input-number', placeholder: '22', @@ -64,6 +64,17 @@ export class SshAccess implements IAccess, ConnectConfig { }) passphrase!: string; + @AccessInput({ + title: '代理', + helper: '代理配置,格式:socks5://$username:$password@$host:$port', + component: { + name: 'a-input', + vModel: 'value', + }, + encrypt: false, + }) + socksProxy!: string; + @AccessInput({ title: '是否Windows', helper: '如果是Windows主机,请勾选此项', diff --git a/packages/ui/certd-server/src/plugins/plugin-host/lib/ssh.ts b/packages/ui/certd-server/src/plugins/plugin-host/lib/ssh.ts index 5533e2fa..a574b09d 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/lib/ssh.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/lib/ssh.ts @@ -5,10 +5,13 @@ import * as _ from 'lodash-es'; import { ILogger } from '@certd/pipeline'; import { SshAccess } from '../access/index.js'; import stripAnsi from 'strip-ansi'; +import { SocksClient } from 'socks'; +import { SocksProxy, SocksProxyType } from 'socks/typings/common/constants.js'; + export class AsyncSsh2Client { conn: ssh2.Client; logger: ILogger; - connConf: ssh2.ConnectConfig; + connConf: SshAccess & ssh2.ConnectConfig; windows = false; encoding: string; constructor(connConf: SshAccess, logger: ILogger) { @@ -27,6 +30,23 @@ export class AsyncSsh2Client { async connect() { this.logger.info(`开始连接,${this.connConf.host}:${this.connConf.port}`); + if (this.connConf.socksProxy) { + this.logger.info(`使用代理${this.connConf.socksProxy}`); + if (typeof this.connConf.port === 'string') { + this.connConf.port = parseInt(this.connConf.port); + } + const proxyOption: SocksProxy = this.parseSocksProxyFromUri(this.connConf.socksProxy); + const info = await SocksClient.createConnection({ + proxy: proxyOption, + command: 'connect', + destination: { + host: this.connConf.host, + port: this.connConf.port, + }, + }); + this.logger.info('代理连接成功'); + this.connConf.sock = info.socket; + } return new Promise((resolve, reject) => { try { const conn = new ssh2.Client(); @@ -160,6 +180,26 @@ export class AsyncSsh2Client { this.conn.end(); } } + + private parseSocksProxyFromUri(socksProxyUri: string): SocksProxy { + const url = new URL(socksProxyUri); + let type: SocksProxyType = 5; + if (url.protocol.startsWith('socks4')) { + type = 4; + } + const proxy: SocksProxy = { + host: url.hostname, + port: parseInt(url.port), + type, + }; + if (url.username) { + proxy.userId = url.username; + } + if (url.password) { + proxy.password = url.password; + } + return proxy; + } } export class SshClient {