🎉 优化系统架构.

This commit is contained in:
lijiahangmax
2025-06-25 18:57:05 +08:00
parent f1ade56e13
commit cec7e21d5a
22 changed files with 667 additions and 118 deletions

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.framework.desensitize.core.annotation.Desensitize;
import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject;
/**
* 终端连接参数
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/26 15:47
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DesensitizeObject
@Schema(name = "TerminalConnectDTO", description = "终端连接参数")
public class TerminalConnectDTO {
@Schema(description = "logId")
private Long logId;
@Schema(description = "连接类型")
private String connectType;
@Schema(description = "hostId")
private Long hostId;
@Schema(description = "hostName")
private String hostName;
@Schema(description = "主机编码")
private String hostCode;
@Schema(description = "主机地址")
private String hostAddress;
@Schema(description = "主机端口")
private Integer hostPort;
@Schema(description = "系统类型")
private String osType;
@Schema(description = "系统架构")
private String archType;
@Schema(description = "超时时间")
private Integer timeout;
@Schema(description = "SSH输出编码")
private String charset;
@Schema(description = "文件名称编码")
private String fileNameCharset;
@Schema(description = "文件内容编码")
private String fileContentCharset;
@Schema(description = "用户名")
private String username;
@Desensitize(toEmpty = true)
@Schema(description = "密码")
private String password;
@Schema(description = "密钥id")
private Long keyId;
@Desensitize(toEmpty = true)
@Schema(description = "公钥文本")
private String publicKey;
@Desensitize(toEmpty = true)
@Schema(description = "私钥文本")
private String privateKey;
@Desensitize(toEmpty = true)
@Schema(description = "私钥密码")
private String privateKeyPassword;
}

View File

@@ -1,155 +0,0 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.jsch;
import cn.orionsec.kit.lang.exception.AuthenticationException;
import cn.orionsec.kit.lang.exception.argument.InvalidArgumentException;
import cn.orionsec.kit.lang.utils.Exceptions;
import cn.orionsec.kit.lang.utils.Strings;
import cn.orionsec.kit.net.host.SessionHolder;
import cn.orionsec.kit.net.host.SessionLogger;
import cn.orionsec.kit.net.host.SessionStore;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.AppConst;
import org.dromara.visor.common.constant.Const;
import org.dromara.visor.common.utils.AesEncryptUtils;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import java.util.Optional;
/**
* sessionStore 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/11 16:58
*/
@Slf4j
public class SessionStores {
protected static final ThreadLocal<String> CURRENT_ADDRESS = new ThreadLocal<>();
/**
* 打开 sessionStore
*
* @param conn conn
* @return sessionStore
*/
public static SessionStore openSessionStore(TerminalConnectDTO conn) {
Long hostId = conn.getHostId();
String address = conn.getHostAddress();
String username = conn.getUsername();
log.info("SessionStores-open-start hostId: {}, address: {}, username: {}", hostId, address, username);
try {
CURRENT_ADDRESS.set(address);
// 创建会话
SessionHolder sessionHolder = SessionHolder.create();
sessionHolder.setLogger(SessionLogger.INFO);
SessionStore session = createSessionStore(conn, sessionHolder);
// 设置版本
session.getSession().setClientVersion("SSH-2.0-ORION_VISOR_V" + AppConst.VERSION);
// 连接
session.connect();
log.info("SessionStores-open-success hostId: {}, address: {}, username: {}", hostId, address, username);
return session;
} catch (Exception e) {
String message = e.getMessage();
log.error("SessionStores-open-error hostId: {}, address: {}, username: {}, message: {}", hostId, address, username, message, e);
throw Exceptions.app(getErrorMessage(e), e);
} finally {
CURRENT_ADDRESS.remove();
}
}
/**
* 创建 sessionStore
*
* @param conn conn
* @param sessionHolder sessionHolder
* @return sessionStore
*/
private static SessionStore createSessionStore(TerminalConnectDTO conn, SessionHolder sessionHolder) {
final boolean useKey = conn.getKeyId() != null;
// 使用密钥认证
if (useKey) {
// 加载密钥
String publicKey = Optional.ofNullable(conn.getPublicKey())
.map(AesEncryptUtils::decryptAsString)
.orElse(null);
String privateKey = Optional.ofNullable(conn.getPrivateKey())
.map(AesEncryptUtils::decryptAsString)
.orElse(null);
String password = Optional.ofNullable(conn.getPrivateKeyPassword())
.map(AesEncryptUtils::decryptAsString)
.orElse(null);
sessionHolder.addIdentityValue(String.valueOf(conn.getKeyId()),
privateKey,
publicKey,
password);
}
// 获取会话
SessionStore session = sessionHolder.getSession(conn.getHostAddress(), conn.getHostPort(), conn.getUsername());
// 使用密码认证
if (!useKey) {
String password = conn.getPassword();
if (!Strings.isEmpty(password)) {
session.password(AesEncryptUtils.decryptAsString(password));
}
}
// 超时时间
session.timeout(conn.getTimeout());
return session;
}
/**
* 获取错误信息
*
* @param e e
* @return errorMessage
*/
private static String getErrorMessage(Exception e) {
if (e == null) {
return null;
}
String host = CURRENT_ADDRESS.get();
String message = e.getMessage();
if (Strings.contains(message, Const.TIMEOUT)) {
// 连接超时
return Strings.format(SessionMessage.CONNECTION_TIMEOUT, host);
} else if (Exceptions.isCausedBy(e, AuthenticationException.class)) {
// 认证失败
return Strings.format(SessionMessage.AUTHENTICATION_FAILURE, host);
} else if (Exceptions.isCausedBy(e, InvalidArgumentException.class)) {
// 参数错误
if (Strings.isBlank(message)) {
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
} else {
return message;
}
} else {
// 其他错误
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
}
}
}