diff --git a/CHANGELOG.md b/CHANGELOG.md index 2059ba640..f8065a161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### 🐣 新增功能 +1. 【server】SSH 终端新增全屏方式打开 + (感谢[@jaseeon](https://gitee.com/jaseeon) [Gitee issues I5BS52](https://gitee.com/dromara/Jpom/issues/I5BS52) ) +2. 【server】SSH 新增超时时间配置(感谢@带刺的玫瑰) + ### 🐞 解决BUG、优化功能 1. 【server】升级 h2 版本,低版本存在漏洞(CVE-2021-23463) diff --git a/modules/server/src/main/java/io/jpom/controller/ssh/SshController.java b/modules/server/src/main/java/io/jpom/controller/ssh/SshController.java index 604ab19af..f92e83eac 100644 --- a/modules/server/src/main/java/io/jpom/controller/ssh/SshController.java +++ b/modules/server/src/main/java/io/jpom/controller/ssh/SshController.java @@ -25,6 +25,7 @@ package io.jpom.controller.ssh; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.text.StrSplitter; +import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; @@ -53,6 +54,7 @@ import io.jpom.permission.SystemPermission; import io.jpom.service.dblog.BuildInfoService; import io.jpom.service.dblog.SshTerminalExecuteLogService; import io.jpom.service.node.ssh.SshService; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.GetMapping; @@ -71,6 +73,7 @@ import java.util.List; @RestController @RequestMapping(value = "node/ssh") @Feature(cls = ClassFeature.SSH) +@Slf4j public class SshController extends BaseServerController { private final SshService sshService; @@ -176,6 +179,8 @@ public class SshController extends BaseServerController { sshModel.setConnectType(connectType.name()); // 获取允许编辑的后缀 String allowEditSuffix = getParameter("allowEditSuffix"); + int timeOut = getParameterInt("timeOut", 5); + sshModel.setTimeOut(timeOut); List allowEditSuffixList = AgentWhitelist.parseToList(allowEditSuffix, "允许编辑的文件后缀不能为空"); sshModel.allowEditSuffix(allowEditSuffixList); try { @@ -205,6 +210,7 @@ public class SshController extends BaseServerController { Session session = SshService.getSessionByModel(sshModel); JschUtil.close(session); } catch (Exception e) { + log.warn("ssh连接失败", e); return JsonMessage.getString(505, "ssh连接失败:" + e.getMessage()); } if (add) { diff --git a/modules/server/src/main/java/io/jpom/model/data/SshModel.java b/modules/server/src/main/java/io/jpom/model/data/SshModel.java index f6ba1a102..84bee6671 100644 --- a/modules/server/src/main/java/io/jpom/model/data/SshModel.java +++ b/modules/server/src/main/java/io/jpom/model/data/SshModel.java @@ -80,6 +80,10 @@ public class SshModel extends BaseWorkspaceModel { * 允许编辑的后缀文件 */ private String allowEditSuffix; + /** + * 节点超时时间 + */ + private Integer timeOut; public SshModel(String id) { this.setId(id); @@ -118,6 +122,18 @@ public class SshModel extends BaseWorkspaceModel { return pas; } + /** + * 超时时间 + * + * @return 最小值 1 分钟 + */ + public int timeOut() { + if (this.timeOut == null) { + return 5; + } + return Math.max(1, this.timeOut); + } + public Charset getCharsetT() { Charset charset; try { diff --git a/modules/server/src/main/java/io/jpom/service/node/ssh/SshService.java b/modules/server/src/main/java/io/jpom/service/node/ssh/SshService.java index 00f2da0f9..845dffebb 100644 --- a/modules/server/src/main/java/io/jpom/service/node/ssh/SshService.java +++ b/modules/server/src/main/java/io/jpom/service/node/ssh/SshService.java @@ -30,6 +30,7 @@ import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.*; import cn.hutool.crypto.SecureUtil; import cn.hutool.extra.ssh.ChannelType; +import cn.hutool.extra.ssh.JschRuntimeException; import cn.hutool.extra.ssh.JschUtil; import cn.hutool.extra.ssh.Sftp; import cn.jiangzeyin.common.spring.SpringUtil; @@ -69,16 +70,16 @@ public class SshService extends BaseWorkspaceService { data.setPrivateKey(null); } - /** - * 获取 ssh 回话 - * - * @param sshId id - * @return session - */ - public static Session getSession(String sshId) { - SshModel sshModel = SpringUtil.getBean(SshService.class).getByKey(sshId, false); - return getSessionByModel(sshModel); - } +// /** +// * 获取 ssh 回话 +// * +// * @param sshId id +// * @return session +// */ +// public static Session getSession(String sshId) { +// SshModel sshModel = SpringUtil.getBean(SshService.class).getByKey(sshId, false); +// return getSessionByModel(sshModel); +// } /** * 获取 ssh 回话 @@ -88,9 +89,10 @@ public class SshService extends BaseWorkspaceService { */ public static Session getSessionByModel(SshModel sshModel) { Session session = null; + int timeOut = (int) TimeUnit.SECONDS.toMillis(sshModel.timeOut()); SshModel.ConnectType connectType = sshModel.connectType(); if (connectType == SshModel.ConnectType.PASS) { - session = JschUtil.openSession(sshModel.getHost(), sshModel.getPort(), sshModel.getUser(), sshModel.getPassword()); + session = JschUtil.openSession(sshModel.getHost(), sshModel.getPort(), sshModel.getUser(), sshModel.getPassword(), timeOut); } else if (connectType == SshModel.ConnectType.PUBKEY) { File rsaFile = null; @@ -126,8 +128,13 @@ public class SshService extends BaseWorkspaceService { if (session == null) { // 简要私钥文件是否存在 Assert.state(FileUtil.isFile(rsaFile), "私钥文件不存在:" + FileUtil.getAbsolutePath(rsaFile)); - session = JschUtil.openSession(sshModel.getHost(), + session = JschUtil.createSession(sshModel.getHost(), sshModel.getPort(), sshModel.getUser(), FileUtil.getAbsolutePath(rsaFile), sshModel.password()); + try { + session.connect(timeOut); + } catch (JSchException e) { + throw new JschRuntimeException(e); + } } } else { throw new IllegalArgumentException("不支持的模式"); diff --git a/modules/sub-plugin/db-h2/src/main/resources/sql/h2-db-v3.1.sql b/modules/sub-plugin/db-h2/src/main/resources/sql/h2-db-v3.1.sql index 774331d3e..65c7c2c08 100644 --- a/modules/sub-plugin/db-h2/src/main/resources/sql/h2-db-v3.1.sql +++ b/modules/sub-plugin/db-h2/src/main/resources/sql/h2-db-v3.1.sql @@ -97,4 +97,9 @@ ALTER TABLE NODE_INFO ALTER TABLE NODE_INFO ADD IF NOT EXISTS httpProxyType VARCHAR(20) comment 'http 代理类型'; +ALTER TABLE SSH_INFO + ADD IF NOT EXISTS timeOut int default 0 comment '节点超时时间'; + + + diff --git a/web-vue/src/api/ssh.js b/web-vue/src/api/ssh.js index 1ad9412fd..d8ed3b273 100644 --- a/web-vue/src/api/ssh.js +++ b/web-vue/src/api/ssh.js @@ -59,6 +59,7 @@ export function editSsh(params) { fileDirs: params.fileDirs, notAllowedCommand: params.notAllowedCommand, allowEditSuffix: params.allowEditSuffix, + timeOut: params.timeOut, }; return axios({ url: "/node/ssh/save.json", diff --git a/web-vue/src/pages/ssh/ssh.vue b/web-vue/src/pages/ssh/ssh.vue index b19675314..4022f024f 100644 --- a/web-vue/src/pages/ssh/ssh.vue +++ b/web-vue/src/pages/ssh/ssh.vue @@ -137,9 +137,7 @@ - - - +