@@ -1,6 +1,6 @@
|
|||||||
version: '3.3'
|
version: '3.3'
|
||||||
|
|
||||||
# latest = 2.4.0
|
# latest = 2.4.1
|
||||||
services:
|
services:
|
||||||
ui:
|
ui:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:latest
|
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:latest
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
docker build -t orion-visor-adminer:${version} .
|
docker build -t orion-visor-adminer:${version} .
|
||||||
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
||||||
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest
|
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM guacamole/guacd:1.5.5
|
FROM guacamole/guacd:1.6.0
|
||||||
USER root
|
USER root
|
||||||
# 系统时区
|
# 系统时区
|
||||||
ARG TZ=Asia/Shanghai
|
ARG TZ=Asia/Shanghai
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
docker build -t orion-visor-guacd:${version} .
|
docker build -t orion-visor-guacd:${version} .
|
||||||
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:${version}
|
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:${version}
|
||||||
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:latest
|
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:latest
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
cp -r ../../sql ./sql
|
cp -r ../../sql ./sql
|
||||||
docker build -t orion-visor-mysql:${version} .
|
docker build -t orion-visor-mysql:${version} .
|
||||||
rm -rf ./sql
|
rm -rf ./sql
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
||||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:${version}
|
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:${version}
|
||||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
docker build -t orion-visor-redis:${version} .
|
docker build -t orion-visor-redis:${version} .
|
||||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
||||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
|
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
|
||||||
docker build -t orion-visor-service:${version} .
|
docker build -t orion-visor-service:${version} .
|
||||||
rm -rf ./orion-visor-launch.jar
|
rm -rf ./orion-visor-launch.jar
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
set -e
|
set -e
|
||||||
version=2.4.0
|
version=2.4.1
|
||||||
mv ../../orion-visor-ui/dist ./dist
|
mv ../../orion-visor-ui/dist ./dist
|
||||||
docker build -t orion-visor-ui:${version} .
|
docker build -t orion-visor-ui:${version} .
|
||||||
rm -rf ./orion-visor-launch.jar
|
rm -rf ./orion-visor-launch.jar
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public interface AppConst extends OrionConst {
|
|||||||
/**
|
/**
|
||||||
* 同 ${orion.version} 迭代时候需要手动更改
|
* 同 ${orion.version} 迭代时候需要手动更改
|
||||||
*/
|
*/
|
||||||
String VERSION = "2.4.0";
|
String VERSION = "2.4.1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同 ${spring.application.name}
|
* 同 ${spring.application.name}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.constant;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.constant.StandardHttpHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http 请求头
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2025/7/1 1:02
|
||||||
|
*/
|
||||||
|
public interface HttpHeaderConst extends StandardHttpHeader {
|
||||||
|
|
||||||
|
String APP_VERSION = "X-App-Version";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -47,6 +47,9 @@ public class RdpConnectConfig extends BaseConnectConfig {
|
|||||||
@Schema(description = "低带宽模式")
|
@Schema(description = "低带宽模式")
|
||||||
private Boolean lowBandwidthMode;
|
private Boolean lowBandwidthMode;
|
||||||
|
|
||||||
|
@Schema(description = "初始化程序")
|
||||||
|
private String initialProgram;
|
||||||
|
|
||||||
@Schema(description = "RDP 版本是否大于8.1")
|
@Schema(description = "RDP 版本是否大于8.1")
|
||||||
private Boolean versionGt81;
|
private Boolean versionGt81;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<url>https://github.com/dromara/orion-visor</url>
|
<url>https://github.com/dromara/orion-visor</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>2.4.0</revision>
|
<revision>2.4.1</revision>
|
||||||
<spring.boot.version>2.7.17</spring.boot.version>
|
<spring.boot.version>2.7.17</spring.boot.version>
|
||||||
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
||||||
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<mockito.inline.version>4.11.0</mockito.inline.version>
|
<mockito.inline.version>4.11.0</mockito.inline.version>
|
||||||
<jedis.mock.version>1.0.7</jedis.mock.version>
|
<jedis.mock.version>1.0.7</jedis.mock.version>
|
||||||
<podam.version>7.2.11.RELEASE</podam.version>
|
<podam.version>7.2.11.RELEASE</podam.version>
|
||||||
<guacd.version>1.5.5</guacd.version>
|
<guacd.version>1.6.0</guacd.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ import java.util.function.Function;
|
|||||||
*/
|
*/
|
||||||
public class ReplaceVersion {
|
public class ReplaceVersion {
|
||||||
|
|
||||||
private static final String TARGET_VERSION = "2.3.9";
|
private static final String TARGET_VERSION = "2.4.0";
|
||||||
|
|
||||||
private static final String REPLACE_VERSION = "2.4.0";
|
private static final String REPLACE_VERSION = "2.4.1";
|
||||||
|
|
||||||
private static final String PATH = new File("").getAbsolutePath();
|
private static final String PATH = new File("").getAbsolutePath();
|
||||||
|
|
||||||
|
|||||||
@@ -56,4 +56,9 @@ public class HostRdpExtraModel implements GenericsDataModel {
|
|||||||
*/
|
*/
|
||||||
private Boolean lowBandwidthMode;
|
private Boolean lowBandwidthMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化程序
|
||||||
|
*/
|
||||||
|
private String initialProgram;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface HostConfigService {
|
public interface HostConfigService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化主机配置
|
||||||
|
*
|
||||||
|
* @param hostId hostId
|
||||||
|
* @param types types
|
||||||
|
*/
|
||||||
|
void initHostConfig(Long hostId, List<String> types);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新主机配置
|
* 更新主机配置
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -67,6 +67,34 @@ public class HostConfigServiceImpl implements HostConfigService {
|
|||||||
@Resource
|
@Resource
|
||||||
private HostConfigDAO hostConfigDAO;
|
private HostConfigDAO hostConfigDAO;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initHostConfig(Long hostId, List<String> types) {
|
||||||
|
// 查询主机配置类型
|
||||||
|
List<String> hostConfigTypes = hostConfigDAO.selectByHostId(hostId)
|
||||||
|
.stream()
|
||||||
|
.map(HostConfigDO::getType)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<HostConfigDO> configs = new ArrayList<>();
|
||||||
|
for (String type : types) {
|
||||||
|
// 配置存在则跳过
|
||||||
|
if (hostConfigTypes.contains(type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 配置不存在则初始化
|
||||||
|
HostConfigDO config = HostConfigDO.builder()
|
||||||
|
.hostId(hostId)
|
||||||
|
.type(type)
|
||||||
|
.status(EnableStatus.ENABLED.name())
|
||||||
|
.config(HostConfigStrategyEnum.of(type).getDefault().serial())
|
||||||
|
.build();
|
||||||
|
configs.add(config);
|
||||||
|
}
|
||||||
|
// 插入主机配置
|
||||||
|
if (!configs.isEmpty()) {
|
||||||
|
hostConfigDAO.insertBatch(configs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer updateHostConfig(HostConfigUpdateRequest request) {
|
public Integer updateHostConfig(HostConfigUpdateRequest request) {
|
||||||
log.info("HostConfigService-updateHostConfig request: {}", request);
|
log.info("HostConfigService-updateHostConfig request: {}", request);
|
||||||
|
|||||||
@@ -293,8 +293,9 @@ public class HostConnectServiceImpl implements HostConnectService {
|
|||||||
// 填充基础主机信息
|
// 填充基础主机信息
|
||||||
this.setBaseConnectConfig(connectConfig, host);
|
this.setBaseConnectConfig(connectConfig, host);
|
||||||
if (extra != null) {
|
if (extra != null) {
|
||||||
// 设置低带宽模式
|
// 设置额外配置信息
|
||||||
connectConfig.setLowBandwidthMode(extra.getLowBandwidthMode());
|
connectConfig.setLowBandwidthMode(extra.getLowBandwidthMode());
|
||||||
|
connectConfig.setInitialProgram(extra.getInitialProgram());
|
||||||
// 获取自定义认证方式
|
// 获取自定义认证方式
|
||||||
HostExtraAuthTypeEnum extraAuthType = HostExtraAuthTypeEnum.of(extra.getAuthType());
|
HostExtraAuthTypeEnum extraAuthType = HostExtraAuthTypeEnum.of(extra.getAuthType());
|
||||||
if (HostExtraAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
|
if (HostExtraAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
|
||||||
|
|||||||
@@ -128,8 +128,10 @@ public class HostServiceImpl implements HostService {
|
|||||||
this.checkHostCodePresent(record);
|
this.checkHostCodePresent(record);
|
||||||
// 插入主机
|
// 插入主机
|
||||||
int effect = hostDAO.insert(record);
|
int effect = hostDAO.insert(record);
|
||||||
log.info("HostService-createHost effect: {}", effect);
|
|
||||||
Long id = record.getId();
|
Long id = record.getId();
|
||||||
|
log.info("HostService-createHost id: {}, effect: {}", id, effect);
|
||||||
|
// 初始化主机配置
|
||||||
|
hostConfigService.initHostConfig(id, request.getTypes());
|
||||||
// 插入 tag
|
// 插入 tag
|
||||||
tagRelApi.addTagRel(TagTypeEnum.HOST, id, request.getTags());
|
tagRelApi.addTagRel(TagTypeEnum.HOST, id, request.getTags());
|
||||||
// 引用分组
|
// 引用分组
|
||||||
@@ -183,6 +185,8 @@ public class HostServiceImpl implements HostService {
|
|||||||
// 修改 config 状态
|
// 修改 config 状态
|
||||||
hostConfigDAO.updateConfigStatus(id, types, EnableStatus.ENABLED.name());
|
hostConfigDAO.updateConfigStatus(id, types, EnableStatus.ENABLED.name());
|
||||||
hostConfigDAO.updateConfigInvertStatus(id, types, EnableStatus.DISABLED.name());
|
hostConfigDAO.updateConfigInvertStatus(id, types, EnableStatus.DISABLED.name());
|
||||||
|
// 初始化主机配置
|
||||||
|
hostConfigService.initHostConfig(id, types);
|
||||||
// 删除缓存
|
// 删除缓存
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
return effect;
|
return effect;
|
||||||
|
|||||||
@@ -22,10 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.common.utils;
|
package org.dromara.visor.module.common.utils;
|
||||||
|
|
||||||
import cn.orionsec.kit.lang.constant.Letters;
|
|
||||||
import cn.orionsec.kit.lang.utils.Booleans;
|
import cn.orionsec.kit.lang.utils.Booleans;
|
||||||
import cn.orionsec.kit.lang.utils.Strings;
|
import cn.orionsec.kit.lang.utils.Strings;
|
||||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
|
||||||
import cn.orionsec.kit.net.host.sftp.SftpExecutor;
|
import cn.orionsec.kit.net.host.sftp.SftpExecutor;
|
||||||
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
||||||
import cn.orionsec.kit.spring.SpringHolder;
|
import cn.orionsec.kit.spring.SpringHolder;
|
||||||
@@ -69,21 +67,4 @@ public class SftpUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取移动目标路径
|
|
||||||
*
|
|
||||||
* @param source source
|
|
||||||
* @param target target
|
|
||||||
* @return absolute target
|
|
||||||
*/
|
|
||||||
public static String getAbsoluteTargetPath(String source, String target) {
|
|
||||||
if (target.charAt(0) == Letters.SLASH) {
|
|
||||||
// 绝对路径
|
|
||||||
return Files1.getPath(Files1.normalize(target));
|
|
||||||
} else {
|
|
||||||
// 相对路径
|
|
||||||
return Files1.getPath(Files1.normalize(Files1.getPath(source + "/../" + target)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.enums.ReturnType;
|
||||||
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||||
@@ -58,7 +59,7 @@ public class AuthenticationController {
|
|||||||
@Resource
|
@Resource
|
||||||
private AuthenticationService authenticationService;
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
@OperatorLog(AuthenticationOperatorType.LOGIN)
|
@OperatorLog(value = AuthenticationOperatorType.LOGIN, ret = ReturnType.IGNORE)
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "登录")
|
@Operation(summary = "登录")
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ package org.dromara.visor.module.infra.controller;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.common.constant.AppConst;
|
||||||
|
import org.dromara.visor.common.constant.HttpHeaderConst;
|
||||||
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||||
@@ -37,6 +39,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +70,12 @@ public class UserAggregateController {
|
|||||||
@IgnoreLog(IgnoreLogMode.RET)
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
@GetMapping("/user")
|
@GetMapping("/user")
|
||||||
@Operation(summary = "获取用户权限聚合信息")
|
@Operation(summary = "获取用户权限聚合信息")
|
||||||
public UserAggregateVO getUserAggregateInfo() {
|
public UserAggregateVO getUserAggregateInfo(HttpServletResponse response) {
|
||||||
|
// FIXME KIT
|
||||||
|
// 设置版本号请求头
|
||||||
|
response.setHeader(HttpHeaderConst.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaderConst.APP_VERSION);
|
||||||
|
response.setHeader(HttpHeaderConst.APP_VERSION, AppConst.VERSION);
|
||||||
|
// 获取用户信息
|
||||||
return userAggregateService.getUserAggregateInfo();
|
return userAggregateService.getUserAggregateInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public interface PreferenceCacheKeyDefine {
|
public interface PreferenceCacheKeyDefine {
|
||||||
|
|
||||||
CacheKeyDefine PREFERENCE = new CacheKeyBuilder()
|
CacheKeyDefine PREFERENCE = new CacheKeyBuilder()
|
||||||
.key("user:prefer:{}:{}")
|
.key("v1:user:prefer:{}:{}")
|
||||||
.desc("用户偏好 ${userId} ${type}")
|
.desc("用户偏好 ${userId} ${type}")
|
||||||
.type(JSONObject.class)
|
.type(JSONObject.class)
|
||||||
.struct(RedisCacheStruct.STRING)
|
.struct(RedisCacheStruct.STRING)
|
||||||
|
|||||||
@@ -49,7 +49,4 @@ public class AppInfoVO implements Serializable {
|
|||||||
@Schema(description = "系统版本")
|
@Schema(description = "系统版本")
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
@Schema(description = "机器码")
|
|
||||||
private String uuid;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
private String newConnectionType;
|
private String newConnectionType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 终端主题
|
* ssh 主题
|
||||||
*/
|
*/
|
||||||
private JSONObject theme;
|
private JSONObject sshTheme;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ssh 显示设置
|
* ssh 显示设置
|
||||||
@@ -61,40 +61,40 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
private JSONObject sshDisplaySetting;
|
private JSONObject sshDisplaySetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rdp 图形化设置
|
* ssh 右键菜单设置
|
||||||
*/
|
*/
|
||||||
private JSONObject rdpGraphSetting;
|
private List<String> sshRightMenuSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ssh 操作栏设置
|
* ssh 操作栏设置
|
||||||
*/
|
*/
|
||||||
private JSONObject sshActionBarSetting;
|
private JSONObject sshActionBarSetting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssh 交互设置
|
||||||
|
*/
|
||||||
|
private JSONObject sshInteractSetting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssh 插件设置
|
||||||
|
*/
|
||||||
|
private JSONObject sshPluginsSetting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdp 会话设置
|
||||||
|
*/
|
||||||
|
private JSONObject rdpSessionSetting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdp 图形化设置
|
||||||
|
*/
|
||||||
|
private JSONObject rdpGraphSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rdp 操作栏设置
|
* rdp 操作栏设置
|
||||||
*/
|
*/
|
||||||
private JSONObject rdpActionBarSetting;
|
private JSONObject rdpActionBarSetting;
|
||||||
|
|
||||||
/**
|
|
||||||
* 右键菜单设置
|
|
||||||
*/
|
|
||||||
private List<String> rightMenuSetting;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 交互设置
|
|
||||||
*/
|
|
||||||
private JSONObject interactSetting;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插件设置
|
|
||||||
*/
|
|
||||||
private JSONObject pluginsSetting;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 会话设置
|
|
||||||
*/
|
|
||||||
private JSONObject sessionSetting;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 快捷键设置
|
* 快捷键设置
|
||||||
*/
|
*/
|
||||||
@@ -148,94 +148,6 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class RdpGraphSettingModel implements IJsonObject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示大小
|
|
||||||
*/
|
|
||||||
private String displaySize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示宽度
|
|
||||||
*/
|
|
||||||
private Integer displayWidth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示高度
|
|
||||||
*/
|
|
||||||
private Integer displayHeight;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用音频输入
|
|
||||||
*/
|
|
||||||
private Boolean enableAudioInput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用音频输出
|
|
||||||
*/
|
|
||||||
private Boolean enableAudioOutput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 颜色深度
|
|
||||||
*/
|
|
||||||
private Integer colorDepth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 无损压缩
|
|
||||||
*/
|
|
||||||
private Boolean forceLossless;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用壁纸
|
|
||||||
*/
|
|
||||||
private Boolean enableWallpaper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用主题
|
|
||||||
*/
|
|
||||||
private Boolean enableTheming;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动平滑字体
|
|
||||||
*/
|
|
||||||
private Boolean enableFontSmoothing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用窗口拖动
|
|
||||||
*/
|
|
||||||
private Boolean enableFullWindowDrag;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用桌面合成
|
|
||||||
*/
|
|
||||||
private Boolean enableDesktopComposition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用菜单动画
|
|
||||||
*/
|
|
||||||
private Boolean enableMenuAnimations;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 禁用位图缓存
|
|
||||||
*/
|
|
||||||
private Boolean disableBitmapCaching;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 禁用离屏缓存
|
|
||||||
*/
|
|
||||||
private Boolean disableOffscreenCaching;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 禁用字形缓存
|
|
||||||
*/
|
|
||||||
private Boolean disableGlyphCaching;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@@ -323,55 +235,7 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class RdpActionBarSettingModel implements IJsonObject {
|
public static class SshInteractSettingModel implements IJsonObject {
|
||||||
|
|
||||||
/**
|
|
||||||
* 位置
|
|
||||||
*/
|
|
||||||
private String position;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示设置
|
|
||||||
*/
|
|
||||||
private Boolean display;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组合键
|
|
||||||
*/
|
|
||||||
private Boolean combinationKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 剪切板
|
|
||||||
*/
|
|
||||||
private Boolean clipboard;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传
|
|
||||||
*/
|
|
||||||
private Boolean upload;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存为 rdp 文件
|
|
||||||
*/
|
|
||||||
private Boolean saveRdp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 断开连接
|
|
||||||
*/
|
|
||||||
private Boolean disconnect;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭
|
|
||||||
*/
|
|
||||||
private Boolean close;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class InteractSettingModel implements IJsonObject {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 快速滚动
|
* 快速滚动
|
||||||
@@ -423,13 +287,23 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
*/
|
*/
|
||||||
private String wordSeparator;
|
private String wordSeparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 伪终端类型
|
||||||
|
*/
|
||||||
|
private String terminalEmulationType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存在缓冲区的行数
|
||||||
|
*/
|
||||||
|
private Integer scrollBackLine;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class PluginsSettingModel implements IJsonObject {
|
public static class SshPluginsSettingModel implements IJsonObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 超链接插件
|
* 超链接插件
|
||||||
@@ -457,17 +331,153 @@ public class TerminalPreferenceModel implements GenericsDataModel {
|
|||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class SessionSettingModel implements IJsonObject {
|
public static class RdpGraphSettingModel implements IJsonObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 伪终端类型
|
* 显示大小
|
||||||
*/
|
*/
|
||||||
private String terminalEmulationType;
|
private String displaySize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存在缓冲区的行数
|
* 显示宽度
|
||||||
*/
|
*/
|
||||||
private Integer scrollBackLine;
|
private Integer displayWidth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示高度
|
||||||
|
*/
|
||||||
|
private Integer displayHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色深度
|
||||||
|
*/
|
||||||
|
private Integer colorDepth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无损压缩
|
||||||
|
*/
|
||||||
|
private Boolean forceLossless;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用壁纸
|
||||||
|
*/
|
||||||
|
private Boolean enableWallpaper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用主题
|
||||||
|
*/
|
||||||
|
private Boolean enableTheming;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动平滑字体
|
||||||
|
*/
|
||||||
|
private Boolean enableFontSmoothing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用窗口拖动
|
||||||
|
*/
|
||||||
|
private Boolean enableFullWindowDrag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用桌面合成
|
||||||
|
*/
|
||||||
|
private Boolean enableDesktopComposition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用菜单动画
|
||||||
|
*/
|
||||||
|
private Boolean enableMenuAnimations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用位图缓存
|
||||||
|
*/
|
||||||
|
private Boolean disableBitmapCaching;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用离屏缓存
|
||||||
|
*/
|
||||||
|
private Boolean disableOffscreenCaching;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用字形缓存
|
||||||
|
*/
|
||||||
|
private Boolean disableGlyphCaching;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用图形加速
|
||||||
|
*/
|
||||||
|
private Boolean disableGfx;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class RdpActionBarSettingModel implements IJsonObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示设置
|
||||||
|
*/
|
||||||
|
private Boolean display;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组合键
|
||||||
|
*/
|
||||||
|
private Boolean combinationKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剪切板
|
||||||
|
*/
|
||||||
|
private Boolean clipboard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传
|
||||||
|
*/
|
||||||
|
private Boolean upload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存为 rdp 文件
|
||||||
|
*/
|
||||||
|
private Boolean saveRdp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开连接
|
||||||
|
*/
|
||||||
|
private Boolean disconnect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭
|
||||||
|
*/
|
||||||
|
private Boolean close;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class RdpSessionSettingModel implements IJsonObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用音频输入
|
||||||
|
*/
|
||||||
|
private Boolean enableAudioInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用音频输出
|
||||||
|
*/
|
||||||
|
private Boolean enableAudioOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动挂载模式
|
||||||
|
*/
|
||||||
|
private String driveMountMode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,23 +51,23 @@ public class TerminalPreferenceStrategy extends AbstractGenericsDataStrategy<Ter
|
|||||||
// 连接类型
|
// 连接类型
|
||||||
.newConnectionType("group")
|
.newConnectionType("group")
|
||||||
// ssh 主题
|
// ssh 主题
|
||||||
.theme(new JSONObject())
|
.sshTheme(new JSONObject())
|
||||||
// ssh 显示设置
|
// ssh 显示设置
|
||||||
.sshDisplaySetting(JSONObject.parseObject(this.getDefaultSshDisplaySetting()))
|
.sshDisplaySetting(JSONObject.parseObject(this.getDefaultSshDisplaySetting()))
|
||||||
// rdp 图形化设置
|
|
||||||
.rdpGraphSetting(JSONObject.parseObject(this.getDefaultRdpGraphSetting()))
|
|
||||||
// ssh 操作栏设置
|
// ssh 操作栏设置
|
||||||
.sshActionBarSetting(JSONObject.parseObject(this.getDefaultSshActionBarSetting()))
|
.sshActionBarSetting(JSONObject.parseObject(this.getDefaultSshActionBarSetting()))
|
||||||
|
// ssh 右键菜单设置
|
||||||
|
.sshRightMenuSetting(this.getDefaultSshRightMenuSetting())
|
||||||
|
// ssh 交互设置
|
||||||
|
.sshInteractSetting(JSONObject.parseObject(this.getDefaultSshInteractSetting()))
|
||||||
|
// ssh 插件设置
|
||||||
|
.sshPluginsSetting(JSONObject.parseObject(this.getDefaultSshPluginsSetting()))
|
||||||
|
// rdp 图形化设置
|
||||||
|
.rdpGraphSetting(JSONObject.parseObject(this.getDefaultRdpGraphSetting()))
|
||||||
// rdp 操作栏设置
|
// rdp 操作栏设置
|
||||||
.rdpActionBarSetting(JSONObject.parseObject(this.getDefaultRdpActionBarSetting()))
|
.rdpActionBarSetting(JSONObject.parseObject(this.getDefaultRdpActionBarSetting()))
|
||||||
// ssh 右键菜单设置
|
// rdp 会话设置
|
||||||
.rightMenuSetting(this.getDefaultRightMenuSetting())
|
.rdpSessionSetting(JSONObject.parseObject(this.getDefaultRdpSessionSetting()))
|
||||||
// 交互设置
|
|
||||||
.interactSetting(JSONObject.parseObject(this.getDefaultInteractSetting()))
|
|
||||||
// 插件设置
|
|
||||||
.pluginsSetting(JSONObject.parseObject(this.getDefaultPluginsSetting()))
|
|
||||||
// 会话设置
|
|
||||||
.sessionSetting(JSONObject.parseObject(this.getDefaultSessionSetting()))
|
|
||||||
// 快捷键设置
|
// 快捷键设置
|
||||||
.shortcutSetting(JSONObject.parseObject(this.getDefaultShortcutSetting()))
|
.shortcutSetting(JSONObject.parseObject(this.getDefaultShortcutSetting()))
|
||||||
.build();
|
.build();
|
||||||
@@ -94,30 +94,12 @@ public class TerminalPreferenceStrategy extends AbstractGenericsDataStrategy<Ter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 rdp 图形化默认设置
|
* 获取 ssh 右键菜单默认设置
|
||||||
*
|
*
|
||||||
* @return setting
|
* @return setting
|
||||||
*/
|
*/
|
||||||
private String getDefaultRdpGraphSetting() {
|
private List<String> getDefaultSshRightMenuSetting() {
|
||||||
return TerminalPreferenceModel.RdpGraphSettingModel.builder()
|
return Lists.of("selectAll", "copy", "paste", "search", "clear");
|
||||||
.displaySize("fit")
|
|
||||||
.displayWidth(0)
|
|
||||||
.displayHeight(0)
|
|
||||||
.colorDepth(24)
|
|
||||||
.enableAudioInput(false)
|
|
||||||
.enableAudioOutput(true)
|
|
||||||
.forceLossless(true)
|
|
||||||
.enableWallpaper(true)
|
|
||||||
.enableTheming(true)
|
|
||||||
.enableFontSmoothing(true)
|
|
||||||
.enableFullWindowDrag(true)
|
|
||||||
.enableDesktopComposition(true)
|
|
||||||
.enableMenuAnimations(false)
|
|
||||||
.disableBitmapCaching(false)
|
|
||||||
.disableOffscreenCaching(false)
|
|
||||||
.disableGlyphCaching(false)
|
|
||||||
.build()
|
|
||||||
.toJsonString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,6 +129,70 @@ public class TerminalPreferenceStrategy extends AbstractGenericsDataStrategy<Ter
|
|||||||
.toJsonString();
|
.toJsonString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 ssh 默认交互设置
|
||||||
|
*
|
||||||
|
* @return setting
|
||||||
|
*/
|
||||||
|
private String getDefaultSshInteractSetting() {
|
||||||
|
return TerminalPreferenceModel.SshInteractSettingModel.builder()
|
||||||
|
.fastScrollModifier(true)
|
||||||
|
.altClickMovesCursor(true)
|
||||||
|
.rightClickSelectsWord(false)
|
||||||
|
.selectionChangeCopy(false)
|
||||||
|
.copyAutoTrim(false)
|
||||||
|
.pasteAutoTrim(false)
|
||||||
|
.rightClickPaste(false)
|
||||||
|
.enableRightClickMenu(true)
|
||||||
|
.enableBell(false)
|
||||||
|
.wordSeparator("/\\()\"'` -.,:;<>~!@#$%^&*|+=[]{}~?│")
|
||||||
|
.terminalEmulationType(TerminalType.XTERM.getType())
|
||||||
|
.scrollBackLine(1000)
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认插件设置
|
||||||
|
*
|
||||||
|
* @return setting
|
||||||
|
*/
|
||||||
|
private String getDefaultSshPluginsSetting() {
|
||||||
|
return TerminalPreferenceModel.SshPluginsSettingModel.builder()
|
||||||
|
.enableWeblinkPlugin(true)
|
||||||
|
.enableWebglPlugin(true)
|
||||||
|
.enableUnicodePlugin(true)
|
||||||
|
.enableImagePlugin(false)
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 rdp 图形化默认设置
|
||||||
|
*
|
||||||
|
* @return setting
|
||||||
|
*/
|
||||||
|
private String getDefaultRdpGraphSetting() {
|
||||||
|
return TerminalPreferenceModel.RdpGraphSettingModel.builder()
|
||||||
|
.displaySize("fit")
|
||||||
|
.displayWidth(0)
|
||||||
|
.displayHeight(0)
|
||||||
|
.colorDepth(24)
|
||||||
|
.forceLossless(true)
|
||||||
|
.enableWallpaper(true)
|
||||||
|
.enableTheming(true)
|
||||||
|
.enableFontSmoothing(true)
|
||||||
|
.enableFullWindowDrag(true)
|
||||||
|
.enableDesktopComposition(true)
|
||||||
|
.enableMenuAnimations(false)
|
||||||
|
.disableBitmapCaching(false)
|
||||||
|
.disableOffscreenCaching(false)
|
||||||
|
.disableGlyphCaching(false)
|
||||||
|
.disableGfx(false)
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 rdp 操作栏默认设置
|
* 获取 rdp 操作栏默认设置
|
||||||
*
|
*
|
||||||
@@ -167,59 +213,15 @@ public class TerminalPreferenceStrategy extends AbstractGenericsDataStrategy<Ter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 ssh 右键菜单默认设置
|
* 获取 rdp 默认会话设置
|
||||||
*
|
*
|
||||||
* @return setting
|
* @return setting
|
||||||
*/
|
*/
|
||||||
private List<String> getDefaultRightMenuSetting() {
|
private String getDefaultRdpSessionSetting() {
|
||||||
return Lists.of("selectAll", "copy", "paste", "search", "clear");
|
return TerminalPreferenceModel.RdpSessionSettingModel.builder()
|
||||||
}
|
.enableAudioInput(false)
|
||||||
|
.enableAudioOutput(true)
|
||||||
/**
|
.driveMountMode("ASSET")
|
||||||
* 获取默认交互设置
|
|
||||||
*
|
|
||||||
* @return setting
|
|
||||||
*/
|
|
||||||
private String getDefaultInteractSetting() {
|
|
||||||
return TerminalPreferenceModel.InteractSettingModel.builder()
|
|
||||||
.fastScrollModifier(true)
|
|
||||||
.altClickMovesCursor(true)
|
|
||||||
.rightClickSelectsWord(false)
|
|
||||||
.selectionChangeCopy(false)
|
|
||||||
.copyAutoTrim(false)
|
|
||||||
.pasteAutoTrim(false)
|
|
||||||
.rightClickPaste(false)
|
|
||||||
.enableRightClickMenu(true)
|
|
||||||
.enableBell(false)
|
|
||||||
.wordSeparator("/\\()\"'` -.,:;<>~!@#$%^&*|+=[]{}~?│")
|
|
||||||
.build()
|
|
||||||
.toJsonString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取默认插件设置
|
|
||||||
*
|
|
||||||
* @return setting
|
|
||||||
*/
|
|
||||||
private String getDefaultPluginsSetting() {
|
|
||||||
return TerminalPreferenceModel.PluginsSettingModel.builder()
|
|
||||||
.enableWeblinkPlugin(true)
|
|
||||||
.enableWebglPlugin(true)
|
|
||||||
.enableUnicodePlugin(true)
|
|
||||||
.enableImagePlugin(false)
|
|
||||||
.build()
|
|
||||||
.toJsonString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取默认会话设置
|
|
||||||
*
|
|
||||||
* @return setting
|
|
||||||
*/
|
|
||||||
private String getDefaultSessionSetting() {
|
|
||||||
return TerminalPreferenceModel.SessionSettingModel.builder()
|
|
||||||
.terminalEmulationType(TerminalType.XTERM.getType())
|
|
||||||
.scrollBackLine(1000)
|
|
||||||
.build()
|
.build()
|
||||||
.toJsonString();
|
.toJsonString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ import org.dromara.visor.module.infra.entity.request.system.SystemSettingUpdateR
|
|||||||
import org.dromara.visor.module.infra.entity.vo.AppInfoVO;
|
import org.dromara.visor.module.infra.entity.vo.AppInfoVO;
|
||||||
import org.dromara.visor.module.infra.entity.vo.RsaKeyPairVO;
|
import org.dromara.visor.module.infra.entity.vo.RsaKeyPairVO;
|
||||||
import org.dromara.visor.module.infra.service.SystemSettingService;
|
import org.dromara.visor.module.infra.service.SystemSettingService;
|
||||||
import org.dromara.visor.module.infra.utils.SystemUuidUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -73,7 +72,6 @@ public class SystemSettingServiceImpl implements SystemSettingService {
|
|||||||
public AppInfoVO getAppInfo() {
|
public AppInfoVO getAppInfo() {
|
||||||
return AppInfoVO.builder()
|
return AppInfoVO.builder()
|
||||||
.version(AppConst.VERSION)
|
.version(AppConst.VERSION)
|
||||||
.uuid(SystemUuidUtils.getSystemUuid())
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,114 +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.infra.utils;
|
|
||||||
|
|
||||||
import cn.orionsec.kit.ext.process.ProcessAwaitExecutor;
|
|
||||||
import cn.orionsec.kit.lang.support.Attempt;
|
|
||||||
import cn.orionsec.kit.lang.utils.Arrays1;
|
|
||||||
import cn.orionsec.kit.lang.utils.Strings;
|
|
||||||
import cn.orionsec.kit.lang.utils.crypto.Signatures;
|
|
||||||
import cn.orionsec.kit.lang.utils.io.Streams;
|
|
||||||
import org.dromara.visor.common.constant.Const;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统 UUID 工具类
|
|
||||||
*
|
|
||||||
* @author Jiahang Li
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025/1/16 11:07
|
|
||||||
*/
|
|
||||||
public class SystemUuidUtils {
|
|
||||||
|
|
||||||
private static String uuid;
|
|
||||||
|
|
||||||
private SystemUuidUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取系统 uuid
|
|
||||||
*
|
|
||||||
* @return uuid
|
|
||||||
*/
|
|
||||||
public static String getSystemUuid() {
|
|
||||||
if (SystemUuidUtils.uuid != null) {
|
|
||||||
return SystemUuidUtils.uuid;
|
|
||||||
}
|
|
||||||
String[][] cmd = new String[][]{
|
|
||||||
new String[]{"/bin/sh", "-c", "cat /sys/class/dmi/id/product_serial"},
|
|
||||||
new String[]{"/bin/bash", "-c", "cat /sys/class/dmi/id/product_serial"},
|
|
||||||
new String[]{"/bin/sh", "-c", "dmidecode -s system-uuid"},
|
|
||||||
new String[]{"/bin/bash", "-c", "dmidecode -s system-uuid"},
|
|
||||||
new String[]{"cmd", "/c", "wmic csproduct get uuid"}
|
|
||||||
};
|
|
||||||
for (String[] s : cmd) {
|
|
||||||
try {
|
|
||||||
String uuid = SystemUuidUtils.getCommandOutput(s);
|
|
||||||
if (Strings.isBlank(uuid)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 去除符号并且转为大写
|
|
||||||
uuid = uuid.replaceAll(Const.DASHED, Const.EMPTY)
|
|
||||||
.toUpperCase()
|
|
||||||
.trim();
|
|
||||||
// 去除 \n
|
|
||||||
String extraUuid = Arrays1.last(uuid.trim().split(Const.LF));
|
|
||||||
if (!Strings.isBlank(extraUuid)) {
|
|
||||||
uuid = extraUuid.trim();
|
|
||||||
}
|
|
||||||
// 去除 :
|
|
||||||
extraUuid = Arrays1.last(uuid.trim().split(Const.COLON));
|
|
||||||
if (!Strings.isBlank(extraUuid)) {
|
|
||||||
uuid = extraUuid.trim();
|
|
||||||
}
|
|
||||||
return SystemUuidUtils.uuid = Signatures.md5(uuid);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// IGNORED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SystemUuidUtils.uuid = Const.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取输出结果
|
|
||||||
*
|
|
||||||
* @param command command
|
|
||||||
* @return result
|
|
||||||
*/
|
|
||||||
public static String getCommandOutput(String[] command) {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
ProcessAwaitExecutor executor = new ProcessAwaitExecutor(command);
|
|
||||||
try {
|
|
||||||
executor.streamHandler(i -> Attempt.uncheck(Streams::transfer, i, out))
|
|
||||||
.waitFor()
|
|
||||||
.sync()
|
|
||||||
.exec();
|
|
||||||
return out.toString();
|
|
||||||
} finally {
|
|
||||||
Streams.close(out);
|
|
||||||
Streams.close(executor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.controller;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.common.validator.group.Page;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
||||||
|
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||||
|
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||||
|
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||||
|
import org.dromara.visor.module.terminal.define.operator.TerminalFileLogOperatorType;
|
||||||
|
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalFileLogQueryRequest;
|
||||||
|
import org.dromara.visor.module.terminal.entity.vo.TerminalFileLogVO;
|
||||||
|
import org.dromara.visor.module.terminal.service.TerminalFileLogService;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件日志操作服务 api
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023-12-26 22:09
|
||||||
|
*/
|
||||||
|
@Tag(name = "terminal - 终端文件日志操作服务")
|
||||||
|
@Slf4j
|
||||||
|
@Validated
|
||||||
|
@RestWrapper
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/terminal/terminal-file-log")
|
||||||
|
public class TerminalFileLogController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TerminalFileLogService terminalFileLogService;
|
||||||
|
|
||||||
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
|
@PostMapping("/query")
|
||||||
|
@Operation(summary = "分页查询终端文件操作日志")
|
||||||
|
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:query', 'terminal:terminal-file-log:management:query')")
|
||||||
|
public DataGrid<TerminalFileLogVO> getTerminalFileLogPage(@Validated(Page.class) @RequestBody TerminalFileLogQueryRequest request) {
|
||||||
|
return terminalFileLogService.getTerminalFileLogPage(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
|
@PostMapping("/count")
|
||||||
|
@Operation(summary = "查询终端文件操作日志数量")
|
||||||
|
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:query', 'terminal:terminal-file-log:management:query')")
|
||||||
|
public Long getTerminalFileLogCount(@Validated @RequestBody TerminalFileLogQueryRequest request) {
|
||||||
|
return terminalFileLogService.getTerminalFileLogCount(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OperatorLog(TerminalFileLogOperatorType.DELETE)
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除终端文件操作日志")
|
||||||
|
@Parameter(name = "idList", description = "idList", required = true)
|
||||||
|
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:delete', 'terminal:terminal-file-log:management:delete')")
|
||||||
|
public Integer deleteTerminalFileLog(@RequestParam("idList") List<Long> idList) {
|
||||||
|
return terminalFileLogService.deleteTerminalFileLog(idList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,22 +22,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.terminal.controller;
|
package org.dromara.visor.module.terminal.controller;
|
||||||
|
|
||||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.visor.common.validator.group.Page;
|
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
|
|
||||||
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||||
import org.dromara.visor.framework.web.core.annotation.IgnoreWrapper;
|
import org.dromara.visor.framework.web.core.annotation.IgnoreWrapper;
|
||||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||||
import org.dromara.visor.module.terminal.define.operator.TerminalOperatorType;
|
|
||||||
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalSftpLogQueryRequest;
|
|
||||||
import org.dromara.visor.module.terminal.entity.vo.TerminalSftpLogVO;
|
|
||||||
import org.dromara.visor.module.terminal.service.TerminalSftpService;
|
import org.dromara.visor.module.terminal.service.TerminalSftpService;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@@ -46,7 +39,6 @@ import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBo
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.annotation.security.PermitAll;
|
import javax.annotation.security.PermitAll;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SFTP 操作服务 api
|
* SFTP 操作服务 api
|
||||||
@@ -66,31 +58,6 @@ public class TerminalSftpController {
|
|||||||
@Resource
|
@Resource
|
||||||
private TerminalSftpService terminalSftpService;
|
private TerminalSftpService terminalSftpService;
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
|
||||||
@PostMapping("/query-log")
|
|
||||||
@Operation(summary = "分页查询 SFTP 操作日志")
|
|
||||||
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:query', 'terminal:terminal-sftp-log:management:query')")
|
|
||||||
public DataGrid<TerminalSftpLogVO> getTerminalSftpLogPage(@Validated(Page.class) @RequestBody TerminalSftpLogQueryRequest request) {
|
|
||||||
return terminalSftpService.getTerminalSftpLogPage(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
|
||||||
@PostMapping("/log-count")
|
|
||||||
@Operation(summary = "查询 SFTP 操作日志数量")
|
|
||||||
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:query', 'terminal:terminal-sftp-log:management:query')")
|
|
||||||
public Long getTerminalSftpLogCount(@Validated @RequestBody TerminalSftpLogQueryRequest request) {
|
|
||||||
return terminalSftpService.getTerminalSftpLogCount(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OperatorLog(TerminalOperatorType.DELETE_SFTP_LOG)
|
|
||||||
@DeleteMapping("/delete-log")
|
|
||||||
@Operation(summary = "删除 SFTP 操作日志")
|
|
||||||
@Parameter(name = "idList", description = "idList", required = true)
|
|
||||||
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:delete', 'terminal:terminal-sftp-log:management:delete')")
|
|
||||||
public Integer deleteTerminalSftpLog(@RequestParam("idList") List<Long> idList) {
|
|
||||||
return terminalSftpService.deleteTerminalSftpLog(idList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
@GetMapping("/get-content")
|
@GetMapping("/get-content")
|
||||||
@Operation(summary = "获取文件内容")
|
@Operation(summary = "获取文件内容")
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.convert;
|
||||||
|
|
||||||
|
import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogDTO;
|
||||||
|
import org.dromara.visor.module.terminal.entity.vo.TerminalFileLogVO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 内部对象转换器
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023-12-26 22:09
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface TerminalFileLogConvert {
|
||||||
|
|
||||||
|
TerminalFileLogConvert MAPPER = Mappers.getMapper(TerminalFileLogConvert.class);
|
||||||
|
|
||||||
|
@Mapping(target = "extra", ignore = true)
|
||||||
|
TerminalFileLogVO to(OperatorLogDTO request);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.define.operator;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.annotation.Module;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件日志 操作日志类型
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/3/2 14:37
|
||||||
|
*/
|
||||||
|
@Module("terminal:terminal-file-log")
|
||||||
|
public class TerminalFileLogOperatorType extends InitializingOperatorTypes {
|
||||||
|
|
||||||
|
public static final String DELETE = "terminal-file-log:delete";
|
||||||
|
|
||||||
|
public static final List<String> TYPES = Lists.of(
|
||||||
|
TerminalOperatorType.SFTP_MKDIR,
|
||||||
|
TerminalOperatorType.SFTP_TOUCH,
|
||||||
|
TerminalOperatorType.SFTP_MOVE,
|
||||||
|
TerminalOperatorType.SFTP_REMOVE,
|
||||||
|
TerminalOperatorType.SFTP_TRUNCATE,
|
||||||
|
TerminalOperatorType.SFTP_CHMOD,
|
||||||
|
TerminalOperatorType.SFTP_CHOWN,
|
||||||
|
TerminalOperatorType.SFTP_CHGRP,
|
||||||
|
TerminalOperatorType.SFTP_GET_CONTENT,
|
||||||
|
TerminalOperatorType.SFTP_SET_CONTENT,
|
||||||
|
TerminalOperatorType.SFTP_UPLOAD,
|
||||||
|
TerminalOperatorType.SFTP_DOWNLOAD,
|
||||||
|
TerminalOperatorType.RDP_UPLOAD,
|
||||||
|
TerminalOperatorType.RDP_DOWNLOAD
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OperatorType[] types() {
|
||||||
|
return new OperatorType[]{
|
||||||
|
new OperatorType(OperatorRiskLevel.H, DELETE, "删除文件操作日志 <sb>${count}</sb> 条"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,14 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.terminal.define.operator;
|
package org.dromara.visor.module.terminal.define.operator;
|
||||||
|
|
||||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.annotation.Module;
|
import org.dromara.visor.framework.biz.operator.log.core.annotation.Module;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel;
|
import org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes;
|
import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType;
|
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 终端 操作日志类型
|
* 终端 操作日志类型
|
||||||
*
|
*
|
||||||
@@ -42,8 +39,6 @@ public class TerminalOperatorType extends InitializingOperatorTypes {
|
|||||||
|
|
||||||
public static final String CONNECT = "terminal:connect";
|
public static final String CONNECT = "terminal:connect";
|
||||||
|
|
||||||
public static final String DELETE_SFTP_LOG = "terminal:delete-sftp-log";
|
|
||||||
|
|
||||||
public static final String SFTP_MKDIR = "terminal:sftp-mkdir";
|
public static final String SFTP_MKDIR = "terminal:sftp-mkdir";
|
||||||
|
|
||||||
public static final String SFTP_TOUCH = "terminal:sftp-touch";
|
public static final String SFTP_TOUCH = "terminal:sftp-touch";
|
||||||
@@ -68,38 +63,28 @@ public class TerminalOperatorType extends InitializingOperatorTypes {
|
|||||||
|
|
||||||
public static final String SFTP_DOWNLOAD = "terminal:sftp-download";
|
public static final String SFTP_DOWNLOAD = "terminal:sftp-download";
|
||||||
|
|
||||||
public static final List<String> SFTP_TYPES = Lists.of(
|
public static final String RDP_UPLOAD = "terminal:rdp-upload";
|
||||||
SFTP_MKDIR,
|
|
||||||
SFTP_TOUCH,
|
public static final String RDP_DOWNLOAD = "terminal:rdp-download";
|
||||||
SFTP_MOVE,
|
|
||||||
SFTP_REMOVE,
|
|
||||||
SFTP_TRUNCATE,
|
|
||||||
SFTP_CHMOD,
|
|
||||||
SFTP_CHOWN,
|
|
||||||
SFTP_CHGRP,
|
|
||||||
SFTP_GET_CONTENT,
|
|
||||||
SFTP_SET_CONTENT,
|
|
||||||
SFTP_UPLOAD,
|
|
||||||
SFTP_DOWNLOAD
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OperatorType[] types() {
|
public OperatorType[] types() {
|
||||||
return new OperatorType[]{
|
return new OperatorType[]{
|
||||||
new OperatorType(OperatorRiskLevel.L, CONNECT, "连接主机 ${connectType} <sb>${hostName}</sb>"),
|
new OperatorType(OperatorRiskLevel.L, CONNECT, "连接主机 ${connectType} <sb>${hostName}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.H, DELETE_SFTP_LOG, "删除 SFTP 操作日志 <sb>${count}</sb> 条"),
|
|
||||||
new OperatorType(OperatorRiskLevel.L, SFTP_MKDIR, "创建文件夹 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.L, SFTP_MKDIR, "创建文件夹 ${hostName} <sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.L, SFTP_TOUCH, "创建文件 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.L, SFTP_TOUCH, "创建文件 ${hostName} <sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_MOVE, "移动文件 ${hostName} <sb>${path}</sb> 至 <sb>${target}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_MOVE, "移动文件 ${hostName} <sb>${path}</sb> 至 <sb>${target}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.H, SFTP_REMOVE, "删除文件 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.H, SFTP_REMOVE, "删除文件 ${hostName} ${count}个\n<sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.H, SFTP_TRUNCATE, "截断文件 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.H, SFTP_TRUNCATE, "截断文件 ${hostName} <sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_CHMOD, "文件提权 ${hostName} <sb>${path}</sb> <sb>${mod}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_CHMOD, "文件提权 ${hostName} <sb>${path}</sb> <sb>${mod}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_CHOWN, "修改文件归属 ${hostName} <sb>${path}</sb> <sb>${id}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_CHOWN, "修改文件归属 ${hostName} <sb>${path}</sb> <sb>${id}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_CHGRP, "修改文件分组 ${hostName} <sb>${path}</sb> <sb>${id}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_CHGRP, "修改文件分组 ${hostName} <sb>${path}</sb> <sb>${id}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.L, SFTP_GET_CONTENT, "获取文件内容 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.L, SFTP_GET_CONTENT, "获取文件内容 ${hostName} <sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_SET_CONTENT, "修改文件内容 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_SET_CONTENT, "修改文件内容 ${hostName} <sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_UPLOAD, "上传文件 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_UPLOAD, "上传文件 ${hostName} (${count}个)\n<sb>${path}</sb>"),
|
||||||
new OperatorType(OperatorRiskLevel.M, SFTP_DOWNLOAD, "下载文件 ${hostName} <sb>${path}</sb>"),
|
new OperatorType(OperatorRiskLevel.M, SFTP_DOWNLOAD, "下载文件 ${hostName} (${count}个)\n<sb>${path}</sb>"),
|
||||||
|
new OperatorType(OperatorRiskLevel.M, RDP_UPLOAD, "上传文件 ${hostName} <sb>${path}</sb>"),
|
||||||
|
new OperatorType(OperatorRiskLevel.M, RDP_DOWNLOAD, "下载文件 ${hostName} <sb>${path}</sb>"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.entity.request.terminal;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import org.dromara.visor.common.entity.BaseQueryRequest;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 查询请求对象
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024-3-4 22:59
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Schema(name = "TerminalFileLogQueryRequest", description = "终端文件操作日志 查询请求对象")
|
||||||
|
public class TerminalFileLogQueryRequest extends BaseQueryRequest {
|
||||||
|
|
||||||
|
@Schema(description = "用户id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "hostId")
|
||||||
|
private Long hostId;
|
||||||
|
|
||||||
|
@Size(max = 64)
|
||||||
|
@Schema(description = "操作类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Schema(description = "操作结果 0失败 1成功")
|
||||||
|
private Integer result;
|
||||||
|
|
||||||
|
@Schema(description = "开始时间-区间")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
private Date[] startTimeRange;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.entity.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 实体对象
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023-10-10 17:08
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Schema(name = "TerminalFileLogVO", description = "终端文件操作日志 实体对象")
|
||||||
|
public class TerminalFileLogVO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "用户id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "用户名")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Schema(description = "主机id")
|
||||||
|
private Long hostId;
|
||||||
|
|
||||||
|
@Schema(description = "主机名称")
|
||||||
|
private String hostName;
|
||||||
|
|
||||||
|
@Schema(description = "主机地址")
|
||||||
|
private String hostAddress;
|
||||||
|
|
||||||
|
@Schema(description = "操作文件")
|
||||||
|
private String[] paths;
|
||||||
|
|
||||||
|
@Schema(description = "请求ip")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Schema(description = "请求地址")
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
@Schema(description = "userAgent")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
@Schema(description = "操作类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Schema(description = "参数")
|
||||||
|
private Map<String, Object> extra;
|
||||||
|
|
||||||
|
@Schema(description = "操作结果 0失败 1成功")
|
||||||
|
private Integer result;
|
||||||
|
|
||||||
|
@Schema(description = "开始时间")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.enums;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.utils.time.Dates;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动挂载模式
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2025/6/29 1:32
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum DriveMountModeEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完全共享
|
||||||
|
*/
|
||||||
|
SHARED("S") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
return this.buildDriveMountPath(DEFAULT_S, userId, DEFAULT_N, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话维度
|
||||||
|
*/
|
||||||
|
SESSION("SE") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
return this.buildDriveMountPath(Dates.current(Dates.YMD2), userId, assetId, sessionId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资产维度
|
||||||
|
*/
|
||||||
|
ASSET("A") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
return this.buildDriveMountPath(DEFAULT_S, userId, assetId, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天维度
|
||||||
|
*/
|
||||||
|
DAY("D") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
return this.buildDriveMountPath(Dates.current(Dates.YMD2), userId, DEFAULT_N, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天维度 + 资产维度
|
||||||
|
*/
|
||||||
|
DAY_ASSET("DA") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
return this.buildDriveMountPath(Dates.current(Dates.YMD2), userId, DEFAULT_N, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 月维度
|
||||||
|
*/
|
||||||
|
MONTH("M") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
String date = Dates.stream()
|
||||||
|
.setDay(1)
|
||||||
|
.format(Dates.YMD2);
|
||||||
|
return this.buildDriveMountPath(date, userId, DEFAULT_N, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 月维度 + 资产维度
|
||||||
|
*/
|
||||||
|
MONTH_ASSET("MA") {
|
||||||
|
@Override
|
||||||
|
public String getDriveMountPath(Long userId, Long assetId, String sessionId) {
|
||||||
|
String date = Dates.stream()
|
||||||
|
.setDay(1)
|
||||||
|
.format(Dates.YMD2);
|
||||||
|
return this.buildDriveMountPath(date, userId, assetId, DEFAULT_S);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Long DEFAULT_N = 0L;
|
||||||
|
|
||||||
|
private static final String DEFAULT_S = "0";
|
||||||
|
|
||||||
|
private final String prefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取驱动挂载路径
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param assetId assetId
|
||||||
|
* @param sessionId sessionId
|
||||||
|
* @return path
|
||||||
|
*/
|
||||||
|
public abstract String getDriveMountPath(Long userId, Long assetId, String sessionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建驱动挂载路径
|
||||||
|
*
|
||||||
|
* @param time time
|
||||||
|
* @param userId userId
|
||||||
|
* @param assetId assetId
|
||||||
|
* @param sessionId sessionId
|
||||||
|
* @return path
|
||||||
|
*/
|
||||||
|
protected String buildDriveMountPath(String time, Long userId, Long assetId, String sessionId) {
|
||||||
|
return prefix + "_"
|
||||||
|
+ time + "_"
|
||||||
|
+ userId + "_"
|
||||||
|
+ assetId + "_"
|
||||||
|
+ sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DriveMountModeEnum of(String mode) {
|
||||||
|
if (mode == null) {
|
||||||
|
return ASSET;
|
||||||
|
}
|
||||||
|
for (DriveMountModeEnum value : values()) {
|
||||||
|
if (value.name().equalsIgnoreCase(mode)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ASSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -306,10 +306,15 @@ public interface GuacdConst {
|
|||||||
String DISABLE_OFFSCREEN_CACHING = "disable-offscreen-caching";
|
String DISABLE_OFFSCREEN_CACHING = "disable-offscreen-caching";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 禁用字形缓存 boolean 默认禁用
|
* 禁用字形缓存 boolean
|
||||||
*/
|
*/
|
||||||
String DISABLE_GLYPH_CACHING = "disable-glyph-caching";
|
String DISABLE_GLYPH_CACHING = "disable-glyph-caching";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用图形加速 boolean
|
||||||
|
*/
|
||||||
|
String DISABLE_GFX = "disable-gfx";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 远程应用名称
|
* 远程应用名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import javax.annotation.PostConstruct;
|
|||||||
public enum InputProtocolEnum {
|
public enum InputProtocolEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接终端
|
* 请求连接
|
||||||
*/
|
*/
|
||||||
CONNECT("co",
|
CONNECT("co",
|
||||||
TerminalConnectHandler.class,
|
TerminalConnectHandler.class,
|
||||||
@@ -74,7 +74,17 @@ public enum InputProtocolEnum {
|
|||||||
new String[]{"type", "width", "height"},
|
new String[]{"type", "width", "height"},
|
||||||
TerminalResizeRequest.class),
|
TerminalResizeRequest.class),
|
||||||
|
|
||||||
// ----------------------- SSH ----------------------
|
// ----------------------- guacd ----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* guacd 指令
|
||||||
|
*/
|
||||||
|
GUACD_INSTRUCTION("gi",
|
||||||
|
GuacdInstructionHandler.class,
|
||||||
|
new String[]{"type", "instruction"},
|
||||||
|
GuacdInstructionRequest.class),
|
||||||
|
|
||||||
|
// ----------------------- ssh ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSH 输入
|
* SSH 输入
|
||||||
@@ -84,7 +94,7 @@ public enum InputProtocolEnum {
|
|||||||
new String[]{"type", "command"},
|
new String[]{"type", "command"},
|
||||||
SshInputRequest.class),
|
SshInputRequest.class),
|
||||||
|
|
||||||
// ----------------------- SFTP ----------------------
|
// ----------------------- sftp ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SFTP 文件列表
|
* SFTP 文件列表
|
||||||
@@ -182,15 +192,15 @@ public enum InputProtocolEnum {
|
|||||||
new String[]{"type", "path"},
|
new String[]{"type", "path"},
|
||||||
SftpBaseRequest.class),
|
SftpBaseRequest.class),
|
||||||
|
|
||||||
// ----------------------- guacd ----------------------
|
// ----------------------- rdp ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* guacd 指令
|
* RDP 文件系统事件
|
||||||
*/
|
*/
|
||||||
GUACD_INSTRUCTION("gi",
|
RDP_FILE_SYSTEM_EVENT("fse",
|
||||||
GuacdInstructionHandler.class,
|
RdpFileSystemEventHandler.class,
|
||||||
new String[]{"type", "instruction"},
|
new String[]{"type", "event"},
|
||||||
GuacdInstructionRequest.class),
|
RdpFileSystemEventRequest.class),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,13 @@ public enum OutputProtocolEnum {
|
|||||||
*/
|
*/
|
||||||
RESIZE("rs", "${type}|${width}|${height}"),
|
RESIZE("rs", "${type}|${width}|${height}"),
|
||||||
|
|
||||||
|
// ----------------------- guacd ----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* guacd 指令
|
||||||
|
*/
|
||||||
|
GUACD_INSTRUCTION("gi", "${type}|${instruction}"),
|
||||||
|
|
||||||
// ----------------------- ssh ----------------------
|
// ----------------------- ssh ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,13 +150,6 @@ public enum OutputProtocolEnum {
|
|||||||
*/
|
*/
|
||||||
SFTP_SET_CONTENT("sc", "${type}|${result}|${msg}|${token}"),
|
SFTP_SET_CONTENT("sc", "${type}|${result}|${msg}|${token}"),
|
||||||
|
|
||||||
// ----------------------- guacd ----------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* guacd 指令
|
|
||||||
*/
|
|
||||||
GUACD_INSTRUCTION("gi", "${type}|${instruction}"),
|
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.handler.terminal.handler;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||||
|
import org.dromara.visor.module.terminal.define.operator.TerminalOperatorType;
|
||||||
|
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
||||||
|
import org.dromara.visor.module.terminal.handler.terminal.model.request.RdpFileSystemEventRequest;
|
||||||
|
import org.dromara.visor.module.terminal.handler.terminal.model.transport.RdpFileSystemEvent;
|
||||||
|
import org.dromara.visor.module.terminal.handler.terminal.sender.IGuacdTerminalSender;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdp 文件系统事件 处理器
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/2/19 11:13
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RdpFileSystemEventHandler extends AbstractTerminalHandler<IGuacdTerminalSender, RdpFileSystemEventRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(TerminalChannelProps props, IGuacdTerminalSender sender, RdpFileSystemEventRequest payload) {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
String sessionId = props.getId();
|
||||||
|
// 获取会话
|
||||||
|
RdpFileSystemEvent fsEvent = JSON.parseObject(payload.getEvent(), RdpFileSystemEvent.class);
|
||||||
|
String event = fsEvent.getEvent();
|
||||||
|
String path = fsEvent.getPath();
|
||||||
|
log.info("RdpFileSystemEventHandler-handle start sessionId: {}, event: {}, path: {}", sessionId, event, path);
|
||||||
|
String operatorType;
|
||||||
|
if (TerminalOperatorType.RDP_UPLOAD.equals(event)) {
|
||||||
|
// 上传文件
|
||||||
|
operatorType = TerminalOperatorType.RDP_UPLOAD;
|
||||||
|
} else if (TerminalOperatorType.RDP_DOWNLOAD.equals(event)) {
|
||||||
|
// 下载文件
|
||||||
|
operatorType = TerminalOperatorType.RDP_DOWNLOAD;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 保存操作日志
|
||||||
|
Map<String, Object> extra = Maps.newMap();
|
||||||
|
extra.put(OperatorLogs.PATH, path);
|
||||||
|
this.saveOperatorLog(props, extra, operatorType, startTime, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpDown
|
|||||||
import org.dromara.visor.module.terminal.handler.terminal.model.response.SftpFileVO;
|
import org.dromara.visor.module.terminal.handler.terminal.model.response.SftpFileVO;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
|
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
|
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
|
||||||
|
import org.dromara.visor.module.terminal.utils.SftpFileUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -50,7 +51,7 @@ public class SftpDownloadFlatDirectoryHandler extends AbstractTerminalHandler<IS
|
|||||||
// 获取会话
|
// 获取会话
|
||||||
String sessionId = props.getId();
|
String sessionId = props.getId();
|
||||||
ISftpSession session = terminalManager.getSession(props.getId());
|
ISftpSession session = terminalManager.getSession(props.getId());
|
||||||
String[] paths = payload.getPath().split("\\|");
|
String[] paths = SftpFileUtils.fromMultiPaths(payload.getPath());
|
||||||
log.info("SftpDownloadFlatDirectoryHandler-handle start sessionId: {}, paths: {}", sessionId, Arrays.toString(paths));
|
log.info("SftpDownloadFlatDirectoryHandler-handle start sessionId: {}, paths: {}", sessionId, Arrays.toString(paths));
|
||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
List<SftpFileVO> files = Lists.empty();
|
List<SftpFileVO> files = Lists.empty();
|
||||||
|
|||||||
@@ -24,12 +24,14 @@ package org.dromara.visor.module.terminal.handler.terminal.handler;
|
|||||||
|
|
||||||
import cn.orionsec.kit.lang.utils.collect.Maps;
|
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.common.constant.Const;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||||
import org.dromara.visor.module.terminal.define.operator.TerminalOperatorType;
|
import org.dromara.visor.module.terminal.define.operator.TerminalOperatorType;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpBaseRequest;
|
import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpBaseRequest;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
|
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
|
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
|
||||||
|
import org.dromara.visor.module.terminal.utils.SftpFileUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -49,11 +51,11 @@ public class SftpRemoveHandler extends AbstractTerminalHandler<ISftpTerminalSend
|
|||||||
@Override
|
@Override
|
||||||
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
|
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
String path = payload.getPath();
|
String[] paths = SftpFileUtils.fromMultiPaths(payload.getPath());
|
||||||
|
String path = String.join(Const.LF, paths);
|
||||||
String sessionId = props.getId();
|
String sessionId = props.getId();
|
||||||
// 获取会话
|
// 获取会话
|
||||||
ISftpSession session = terminalManager.getSession(sessionId);
|
ISftpSession session = terminalManager.getSession(sessionId);
|
||||||
String[] paths = path.split("\\|");
|
|
||||||
log.info("SftpRemoveHandler-handle start sessionId: {}, path: {}", sessionId, Arrays.toString(paths));
|
log.info("SftpRemoveHandler-handle start sessionId: {}, path: {}", sessionId, Arrays.toString(paths));
|
||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
// 删除
|
// 删除
|
||||||
@@ -69,6 +71,7 @@ public class SftpRemoveHandler extends AbstractTerminalHandler<ISftpTerminalSend
|
|||||||
// 保存操作日志
|
// 保存操作日志
|
||||||
Map<String, Object> extra = Maps.newMap();
|
Map<String, Object> extra = Maps.newMap();
|
||||||
extra.put(OperatorLogs.PATH, path);
|
extra.put(OperatorLogs.PATH, path);
|
||||||
|
extra.put(OperatorLogs.COUNT, paths.length);
|
||||||
this.saveOperatorLog(props,
|
this.saveOperatorLog(props,
|
||||||
extra, TerminalOperatorType.SFTP_REMOVE,
|
extra, TerminalOperatorType.SFTP_REMOVE,
|
||||||
startTime, ex);
|
startTime, ex);
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<ITerminalSen
|
|||||||
this.updateTerminalConnectLog(logId, null, null);
|
this.updateTerminalConnectLog(logId, null, null);
|
||||||
// 发送设置信息
|
// 发送设置信息
|
||||||
sender.sendSetInfo(TerminalSetInfo.builder()
|
sender.sendSetInfo(TerminalSetInfo.builder()
|
||||||
|
.logId(logId)
|
||||||
.address(connectConfig.getHostAddress())
|
.address(connectConfig.getHostAddress())
|
||||||
.port(connectConfig.getHostPort())
|
.port(connectConfig.getHostPort())
|
||||||
.username(connectConfig.getUsername())
|
.username(connectConfig.getUsername())
|
||||||
|
|||||||
@@ -126,6 +126,16 @@ public class TerminalChannelExtra {
|
|||||||
*/
|
*/
|
||||||
private Boolean disableGlyphCaching;
|
private Boolean disableGlyphCaching;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用图形加速
|
||||||
|
*/
|
||||||
|
private Boolean disableGfx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动挂载模式
|
||||||
|
*/
|
||||||
|
private String driveMountMode;
|
||||||
|
|
||||||
// -------------------- vnc --------------------
|
// -------------------- vnc --------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.handler.terminal.model.request;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalBasePayload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdp 文件系统事件请求
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/2/6 13:31
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class RdpFileSystemEventRequest extends TerminalBasePayload {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件
|
||||||
|
*/
|
||||||
|
private String event;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.handler.terminal.model.transport;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RDP 文件系统事件
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2025/6/30 22:33
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RdpFileSystemEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件
|
||||||
|
*/
|
||||||
|
private String event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件路径
|
||||||
|
*/
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -41,6 +41,11 @@ import lombok.experimental.SuperBuilder;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class TerminalSetInfo implements IJsonObject {
|
public class TerminalSetInfo implements IJsonObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logId
|
||||||
|
*/
|
||||||
|
private Long logId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 地址
|
* 地址
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ package org.dromara.visor.module.terminal.handler.terminal.session;
|
|||||||
import cn.orionsec.kit.lang.utils.Booleans;
|
import cn.orionsec.kit.lang.utils.Booleans;
|
||||||
import cn.orionsec.kit.lang.utils.Strings;
|
import cn.orionsec.kit.lang.utils.Strings;
|
||||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
import cn.orionsec.kit.lang.utils.io.Files1;
|
||||||
import cn.orionsec.kit.lang.utils.time.Dates;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.visor.common.constant.AppConst;
|
import org.dromara.visor.common.constant.AppConst;
|
||||||
import org.dromara.visor.common.utils.AesEncryptUtils;
|
import org.dromara.visor.common.utils.AesEncryptUtils;
|
||||||
import org.dromara.visor.module.common.config.GuacdConfig;
|
import org.dromara.visor.module.common.config.GuacdConfig;
|
||||||
|
import org.dromara.visor.module.terminal.enums.DriveMountModeEnum;
|
||||||
import org.dromara.visor.module.terminal.handler.guacd.GuacdTunnel;
|
import org.dromara.visor.module.terminal.handler.guacd.GuacdTunnel;
|
||||||
import org.dromara.visor.module.terminal.handler.guacd.IGuacdTunnel;
|
import org.dromara.visor.module.terminal.handler.guacd.IGuacdTunnel;
|
||||||
import org.dromara.visor.module.terminal.handler.guacd.constant.GuacdConst;
|
import org.dromara.visor.module.terminal.handler.guacd.constant.GuacdConst;
|
||||||
@@ -101,9 +101,10 @@ public class RdpSession extends AbstractGuacdSession<TerminalSessionRdpConfig> i
|
|||||||
tunnel.setParameter(GuacdConst.ENABLE_FULL_WINDOW_DRAG, extra.getEnableFullWindowDrag());
|
tunnel.setParameter(GuacdConst.ENABLE_FULL_WINDOW_DRAG, extra.getEnableFullWindowDrag());
|
||||||
tunnel.setParameter(GuacdConst.ENABLE_DESKTOP_COMPOSITION, extra.getEnableDesktopComposition());
|
tunnel.setParameter(GuacdConst.ENABLE_DESKTOP_COMPOSITION, extra.getEnableDesktopComposition());
|
||||||
tunnel.setParameter(GuacdConst.ENABLE_MENU_ANIMATIONS, extra.getEnableMenuAnimations());
|
tunnel.setParameter(GuacdConst.ENABLE_MENU_ANIMATIONS, extra.getEnableMenuAnimations());
|
||||||
|
tunnel.setParameter(GuacdConst.DISABLE_BITMAP_CACHING, extra.getDisableBitmapCaching());
|
||||||
tunnel.setParameter(GuacdConst.DISABLE_OFFSCREEN_CACHING, extra.getDisableOffscreenCaching());
|
tunnel.setParameter(GuacdConst.DISABLE_OFFSCREEN_CACHING, extra.getDisableOffscreenCaching());
|
||||||
tunnel.setParameter(GuacdConst.DISABLE_GLYPH_CACHING, extra.getDisableGlyphCaching());
|
tunnel.setParameter(GuacdConst.DISABLE_GLYPH_CACHING, extra.getDisableGlyphCaching());
|
||||||
tunnel.setParameter(GuacdConst.DISABLE_BITMAP_CACHING, extra.getDisableBitmapCaching());
|
tunnel.setParameter(GuacdConst.DISABLE_GFX, extra.getDisableGfx());
|
||||||
// 音频
|
// 音频
|
||||||
tunnel.setAudioMimeTypes(GuacdConst.AUDIO_MIMETYPES);
|
tunnel.setAudioMimeTypes(GuacdConst.AUDIO_MIMETYPES);
|
||||||
tunnel.setParameter(GuacdConst.ENABLE_AUDIO_INPUT, extra.getEnableAudioInput());
|
tunnel.setParameter(GuacdConst.ENABLE_AUDIO_INPUT, extra.getEnableAudioInput());
|
||||||
@@ -113,8 +114,15 @@ public class RdpSession extends AbstractGuacdSession<TerminalSessionRdpConfig> i
|
|||||||
tunnel.setParameter(GuacdConst.ENABLE_DRIVE, true);
|
tunnel.setParameter(GuacdConst.ENABLE_DRIVE, true);
|
||||||
tunnel.setParameter(GuacdConst.CREATE_DRIVE_PATH, true);
|
tunnel.setParameter(GuacdConst.CREATE_DRIVE_PATH, true);
|
||||||
tunnel.setParameter(GuacdConst.DRIVE_NAME, GuacdConst.DRIVE_DRIVE_NAME);
|
tunnel.setParameter(GuacdConst.DRIVE_NAME, GuacdConst.DRIVE_DRIVE_NAME);
|
||||||
// 父文件夹必须存在 所以只能用 _ 分
|
// 父文件夹必须存在 否则会报错 所以不能分层
|
||||||
tunnel.setParameter(GuacdConst.DRIVE_PATH, Files1.getPath(guacdConfig.getDrivePath() + "/" + Dates.current(Dates.YMD2) + "_" + props.getUserId() + "_" + props.getHostId()));
|
String driveMountPath = DriveMountModeEnum.of(extra.getDriveMountMode())
|
||||||
|
.getDriveMountPath(props.getUserId(), props.getHostId(), props.getId());
|
||||||
|
tunnel.setParameter(GuacdConst.DRIVE_PATH, Files1.getPath(guacdConfig.getDrivePath() + "/" + driveMountPath));
|
||||||
|
// 初始化程序
|
||||||
|
String initialProgram = config.getInitialProgram();
|
||||||
|
if (!Strings.isBlank(initialProgram)) {
|
||||||
|
tunnel.setParameter(GuacdConst.INITIAL_PROGRAM, initialProgram);
|
||||||
|
}
|
||||||
// 预连接
|
// 预连接
|
||||||
String preConnectionId = config.getPreConnectionId();
|
String preConnectionId = config.getPreConnectionId();
|
||||||
if (!Strings.isBlank(preConnectionId)) {
|
if (!Strings.isBlank(preConnectionId)) {
|
||||||
@@ -153,8 +161,9 @@ public class RdpSession extends AbstractGuacdSession<TerminalSessionRdpConfig> i
|
|||||||
extra.setEnableDesktopComposition(false);
|
extra.setEnableDesktopComposition(false);
|
||||||
extra.setEnableMenuAnimations(false);
|
extra.setEnableMenuAnimations(false);
|
||||||
extra.setDisableBitmapCaching(false);
|
extra.setDisableBitmapCaching(false);
|
||||||
|
extra.setDisableOffscreenCaching(false);
|
||||||
extra.setDisableGlyphCaching(false);
|
extra.setDisableGlyphCaching(false);
|
||||||
extra.setDisableBitmapCaching(false);
|
extra.setDisableGfx(false);
|
||||||
extra.setEnableAudioInput(false);
|
extra.setEnableAudioInput(false);
|
||||||
extra.setEnableAudioOutput(false);
|
extra.setEnableAudioOutput(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.dromara.visor.common.constant.Const;
|
import org.dromara.visor.common.constant.Const;
|
||||||
import org.dromara.visor.common.constant.ErrorMessage;
|
import org.dromara.visor.common.constant.ErrorMessage;
|
||||||
import org.dromara.visor.common.utils.Valid;
|
import org.dromara.visor.common.utils.Valid;
|
||||||
import org.dromara.visor.module.common.utils.SftpUtils;
|
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.model.config.TerminalSessionSftpConfig;
|
import org.dromara.visor.module.terminal.handler.terminal.model.config.TerminalSessionSftpConfig;
|
||||||
import org.dromara.visor.module.terminal.handler.terminal.model.response.SftpFileVO;
|
import org.dromara.visor.module.terminal.handler.terminal.model.response.SftpFileVO;
|
||||||
@@ -117,7 +116,7 @@ public class SftpSession extends AbstractTerminalSession<ISftpTerminalSender, Te
|
|||||||
public void move(String source, String target) {
|
public void move(String source, String target) {
|
||||||
// 计算路径
|
// 计算路径
|
||||||
source = Valid.checkNormalize(source);
|
source = Valid.checkNormalize(source);
|
||||||
target = SftpUtils.getAbsoluteTargetPath(source, target);
|
target = SftpFileUtils.getAbsoluteTargetPath(source, target);
|
||||||
// 移动
|
// 移动
|
||||||
executor.move(source, target);
|
executor.move(source, target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件操作请求 实体对象
|
* 文件操作请求 实体对象
|
||||||
*
|
*
|
||||||
@@ -42,6 +40,11 @@ import java.util.List;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class TransferOperatorRequest {
|
public class TransferOperatorRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志id
|
||||||
|
*/
|
||||||
|
private Long logId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件路径
|
* 文件路径
|
||||||
*/
|
*/
|
||||||
@@ -62,11 +65,6 @@ public class TransferOperatorRequest {
|
|||||||
*/
|
*/
|
||||||
private Long hostId;
|
private Long hostId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 被压缩文件路径
|
|
||||||
*/
|
|
||||||
private List<String> paths;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 错误信息 后端赋值
|
* 错误信息 后端赋值
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ package org.dromara.visor.module.terminal.handler.transfer.session;
|
|||||||
import cn.orionsec.kit.lang.define.wrapper.Ref;
|
import cn.orionsec.kit.lang.define.wrapper.Ref;
|
||||||
import cn.orionsec.kit.lang.utils.Threads;
|
import cn.orionsec.kit.lang.utils.Threads;
|
||||||
import cn.orionsec.kit.lang.utils.Valid;
|
import cn.orionsec.kit.lang.utils.Valid;
|
||||||
|
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||||
import cn.orionsec.kit.lang.utils.io.Streams;
|
import cn.orionsec.kit.lang.utils.io.Streams;
|
||||||
import cn.orionsec.kit.net.host.SessionStore;
|
import cn.orionsec.kit.net.host.SessionStore;
|
||||||
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
||||||
@@ -72,7 +73,7 @@ public class DownloadSession extends TransferSession implements StreamingRespons
|
|||||||
super.onStart(request);
|
super.onStart(request);
|
||||||
log.info("DownloadSession.startDownload open start channelId: {}, path: {}", channelId, path);
|
log.info("DownloadSession.startDownload open start channelId: {}, path: {}", channelId, path);
|
||||||
// 保存操作日志
|
// 保存操作日志
|
||||||
this.saveOperatorLog(TerminalOperatorType.SFTP_DOWNLOAD, path);
|
this.saveOperatorLog(request.getLogId(), TerminalOperatorType.SFTP_DOWNLOAD, Lists.singleton(path));
|
||||||
// 检查连接
|
// 检查连接
|
||||||
this.init();
|
this.init();
|
||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import cn.orionsec.kit.net.host.sftp.SftpExecutor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.common.constant.Const;
|
||||||
import org.dromara.visor.common.constant.FieldConst;
|
import org.dromara.visor.common.constant.FieldConst;
|
||||||
import org.dromara.visor.common.session.config.SshConnectConfig;
|
import org.dromara.visor.common.session.config.SshConnectConfig;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorLogModel;
|
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorLogModel;
|
||||||
@@ -43,6 +44,7 @@ import org.dromara.visor.module.terminal.handler.transfer.model.TransferOperator
|
|||||||
import org.dromara.visor.module.terminal.handler.transfer.utils.TransferUtils;
|
import org.dromara.visor.module.terminal.handler.transfer.utils.TransferUtils;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,20 +149,25 @@ public abstract class TransferSession implements ITransferSession {
|
|||||||
/**
|
/**
|
||||||
* 保存操作日志
|
* 保存操作日志
|
||||||
*
|
*
|
||||||
* @param type type
|
* @param logId logId
|
||||||
* @param path path
|
* @param type type
|
||||||
|
* @param paths paths
|
||||||
*/
|
*/
|
||||||
protected void saveOperatorLog(String type, String path) {
|
protected void saveOperatorLog(Long logId, String type, List<String> paths) {
|
||||||
// 设置参数
|
TerminalChannelProps props = WebSockets.getAttr(channel, FieldConst.PROPS);
|
||||||
|
String path = String.join(Const.LF, paths);
|
||||||
|
int count = paths.size();
|
||||||
|
// 获取操作日志
|
||||||
Map<String, Object> extra = Maps.newMap();
|
Map<String, Object> extra = Maps.newMap();
|
||||||
extra.put(OperatorLogs.PATH, path);
|
extra.put(OperatorLogs.PATH, path);
|
||||||
|
extra.put(OperatorLogs.COUNT, count);
|
||||||
extra.put(OperatorLogs.HOST_ID, connectConfig.getHostId());
|
extra.put(OperatorLogs.HOST_ID, connectConfig.getHostId());
|
||||||
extra.put(OperatorLogs.HOST_NAME, connectConfig.getHostName());
|
extra.put(OperatorLogs.HOST_NAME, connectConfig.getHostName());
|
||||||
extra.put(OperatorLogs.ADDRESS, connectConfig.getHostAddress());
|
extra.put(OperatorLogs.ADDRESS, connectConfig.getHostAddress());
|
||||||
// 获取日志
|
|
||||||
TerminalChannelProps props = WebSockets.getAttr(channel, FieldConst.PROPS);
|
|
||||||
OperatorLogModel model = TerminalUtils.getOperatorLogModel(props, extra, type, System.currentTimeMillis(), null);
|
OperatorLogModel model = TerminalUtils.getOperatorLogModel(props, extra, type, System.currentTimeMillis(), null);
|
||||||
// 保存
|
// 保存操作日志
|
||||||
|
TerminalAsyncSaver.saveOperatorLog(model);
|
||||||
|
// 保存操作日志
|
||||||
TerminalAsyncSaver.saveOperatorLog(model);
|
TerminalAsyncSaver.saveOperatorLog(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.terminal.handler.transfer.session;
|
package org.dromara.visor.module.terminal.handler.transfer.session;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||||
import cn.orionsec.kit.lang.utils.io.Streams;
|
import cn.orionsec.kit.lang.utils.io.Streams;
|
||||||
import cn.orionsec.kit.net.host.SessionStore;
|
import cn.orionsec.kit.net.host.SessionStore;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -58,7 +59,7 @@ public class UploadSession extends TransferSession {
|
|||||||
try {
|
try {
|
||||||
log.info("UploadSession.startUpload start channelId: {}, path: {}", channelId, path);
|
log.info("UploadSession.startUpload start channelId: {}, path: {}", channelId, path);
|
||||||
// 保存操作日志
|
// 保存操作日志
|
||||||
this.saveOperatorLog(TerminalOperatorType.SFTP_UPLOAD, path);
|
this.saveOperatorLog(request.getLogId(), TerminalOperatorType.SFTP_UPLOAD, Lists.singleton(path));
|
||||||
// 检查连接
|
// 检查连接
|
||||||
this.init();
|
this.init();
|
||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.service;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||||
|
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalFileLogQueryRequest;
|
||||||
|
import org.dromara.visor.module.terminal.entity.vo.TerminalFileLogVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件日志服务类
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023-12-26 22:09
|
||||||
|
*/
|
||||||
|
public interface TerminalFileLogService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询终端文件操作日志
|
||||||
|
*
|
||||||
|
* @param request request
|
||||||
|
* @return rows
|
||||||
|
*/
|
||||||
|
DataGrid<TerminalFileLogVO> getTerminalFileLogPage(TerminalFileLogQueryRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取终端文件操作日志数量
|
||||||
|
*
|
||||||
|
* @param request request
|
||||||
|
* @return count
|
||||||
|
*/
|
||||||
|
Long getTerminalFileLogCount(TerminalFileLogQueryRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除终端文件操作日志
|
||||||
|
*
|
||||||
|
* @param idList idList
|
||||||
|
* @return effect
|
||||||
|
*/
|
||||||
|
Integer deleteTerminalFileLog(List<Long> idList);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,15 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.terminal.service;
|
package org.dromara.visor.module.terminal.service;
|
||||||
|
|
||||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
|
||||||
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalSftpLogQueryRequest;
|
|
||||||
import org.dromara.visor.module.terminal.entity.vo.TerminalSftpLogVO;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SFTP 操作 服务类
|
* SFTP 操作 服务类
|
||||||
@@ -41,30 +37,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface TerminalSftpService {
|
public interface TerminalSftpService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询 SFTP 操作日志
|
|
||||||
*
|
|
||||||
* @param request request
|
|
||||||
* @return rows
|
|
||||||
*/
|
|
||||||
DataGrid<TerminalSftpLogVO> getTerminalSftpLogPage(TerminalSftpLogQueryRequest request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 SFTP 操作日志数量
|
|
||||||
*
|
|
||||||
* @param request request
|
|
||||||
* @return count
|
|
||||||
*/
|
|
||||||
Long getTerminalSftpLogCount(TerminalSftpLogQueryRequest request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除 SFTP 操作日志
|
|
||||||
*
|
|
||||||
* @param idList idList
|
|
||||||
* @return effect
|
|
||||||
*/
|
|
||||||
Integer deleteTerminalSftpLog(List<Long> idList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置文件内容
|
* 设置文件内容
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* 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.terminal.service.impl;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||||
|
import cn.orionsec.kit.lang.utils.Arrays1;
|
||||||
|
import cn.orionsec.kit.lang.utils.Strings;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.visor.common.constant.ExtraFieldConst;
|
||||||
|
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||||
|
import org.dromara.visor.module.infra.api.OperatorLogApi;
|
||||||
|
import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogQueryDTO;
|
||||||
|
import org.dromara.visor.module.terminal.convert.TerminalFileLogConvert;
|
||||||
|
import org.dromara.visor.module.terminal.define.operator.TerminalFileLogOperatorType;
|
||||||
|
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalFileLogQueryRequest;
|
||||||
|
import org.dromara.visor.module.terminal.entity.vo.TerminalFileLogVO;
|
||||||
|
import org.dromara.visor.module.terminal.service.TerminalFileLogService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件日志服务实现类
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/3/4 23:35
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class TerminalFileLogServiceImpl implements TerminalFileLogService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OperatorLogApi operatorLogApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataGrid<TerminalFileLogVO> getTerminalFileLogPage(TerminalFileLogQueryRequest request) {
|
||||||
|
// 查询
|
||||||
|
OperatorLogQueryDTO query = this.buildQueryInfo(request);
|
||||||
|
// 转换
|
||||||
|
return operatorLogApi.getOperatorLogPage(query)
|
||||||
|
.map(s -> {
|
||||||
|
JSONObject extra = JSON.parseObject(s.getExtra());
|
||||||
|
TerminalFileLogVO vo = TerminalFileLogConvert.MAPPER.to(s);
|
||||||
|
vo.setHostId(extra.getLong(ExtraFieldConst.HOST_ID));
|
||||||
|
vo.setHostName(extra.getString(ExtraFieldConst.HOST_NAME));
|
||||||
|
vo.setHostAddress(extra.getString(ExtraFieldConst.ADDRESS));
|
||||||
|
String[] paths = Optional.ofNullable(extra.getString(ExtraFieldConst.PATH))
|
||||||
|
.map(p -> p.split("\\|"))
|
||||||
|
.orElse(new String[0]);
|
||||||
|
vo.setPaths(paths);
|
||||||
|
vo.setExtra(extra);
|
||||||
|
return vo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTerminalFileLogCount(TerminalFileLogQueryRequest request) {
|
||||||
|
// 查询
|
||||||
|
OperatorLogQueryDTO query = this.buildQueryInfo(request);
|
||||||
|
// 转换
|
||||||
|
return operatorLogApi.getOperatorLogCount(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer deleteTerminalFileLog(List<Long> idList) {
|
||||||
|
log.info("TerminalSftpService.deleteTerminalFileLog start {}", JSON.toJSONString(idList));
|
||||||
|
Integer effect = operatorLogApi.deleteOperatorLog(idList);
|
||||||
|
log.info("TerminalSftpService.deleteTerminalFileLog finish {}", effect);
|
||||||
|
// 设置日志参数
|
||||||
|
OperatorLogs.add(OperatorLogs.COUNT, effect);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建查询对象
|
||||||
|
*
|
||||||
|
* @param request request
|
||||||
|
* @return query
|
||||||
|
*/
|
||||||
|
private OperatorLogQueryDTO buildQueryInfo(TerminalFileLogQueryRequest request) {
|
||||||
|
Long hostId = request.getHostId();
|
||||||
|
String type = request.getType();
|
||||||
|
// 构建参数
|
||||||
|
OperatorLogQueryDTO query = OperatorLogQueryDTO.builder()
|
||||||
|
.userId(request.getUserId())
|
||||||
|
.result(request.getResult())
|
||||||
|
.startTimeStart(Arrays1.getIfPresent(request.getStartTimeRange(), 0))
|
||||||
|
.startTimeEnd(Arrays1.getIfPresent(request.getStartTimeRange(), 1))
|
||||||
|
.build();
|
||||||
|
query.setPage(request.getPage());
|
||||||
|
query.setLimit(request.getLimit());
|
||||||
|
query.setOrder(request.getOrder());
|
||||||
|
if (Strings.isBlank(type)) {
|
||||||
|
// 查询全部文件操作类型
|
||||||
|
query.setTypeList(TerminalFileLogOperatorType.TYPES);
|
||||||
|
} else {
|
||||||
|
query.setType(type);
|
||||||
|
}
|
||||||
|
// 模糊查询
|
||||||
|
if (hostId != null) {
|
||||||
|
query.setExtra("\"hostId\": " + hostId + ",");
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,9 +23,7 @@
|
|||||||
package org.dromara.visor.module.terminal.service.impl;
|
package org.dromara.visor.module.terminal.service.impl;
|
||||||
|
|
||||||
import cn.orionsec.kit.lang.constant.StandardContentType;
|
import cn.orionsec.kit.lang.constant.StandardContentType;
|
||||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
|
||||||
import cn.orionsec.kit.lang.define.wrapper.HttpWrapper;
|
import cn.orionsec.kit.lang.define.wrapper.HttpWrapper;
|
||||||
import cn.orionsec.kit.lang.utils.Arrays1;
|
|
||||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||||
import cn.orionsec.kit.lang.utils.Strings;
|
import cn.orionsec.kit.lang.utils.Strings;
|
||||||
import cn.orionsec.kit.lang.utils.Valid;
|
import cn.orionsec.kit.lang.utils.Valid;
|
||||||
@@ -34,27 +32,17 @@ import cn.orionsec.kit.lang.utils.io.Streams;
|
|||||||
import cn.orionsec.kit.net.host.SessionStore;
|
import cn.orionsec.kit.net.host.SessionStore;
|
||||||
import cn.orionsec.kit.net.host.sftp.SftpExecutor;
|
import cn.orionsec.kit.net.host.sftp.SftpExecutor;
|
||||||
import cn.orionsec.kit.web.servlet.web.Servlets;
|
import cn.orionsec.kit.web.servlet.web.Servlets;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.visor.common.constant.Const;
|
import org.dromara.visor.common.constant.Const;
|
||||||
import org.dromara.visor.common.constant.ErrorMessage;
|
import org.dromara.visor.common.constant.ErrorMessage;
|
||||||
import org.dromara.visor.common.constant.ExtraFieldConst;
|
|
||||||
import org.dromara.visor.common.session.config.SshConnectConfig;
|
import org.dromara.visor.common.session.config.SshConnectConfig;
|
||||||
import org.dromara.visor.common.session.ssh.SessionStores;
|
import org.dromara.visor.common.session.ssh.SessionStores;
|
||||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
|
||||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||||
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
import org.dromara.visor.framework.security.core.utils.SecurityUtils;
|
||||||
import org.dromara.visor.module.asset.api.HostConnectApi;
|
import org.dromara.visor.module.asset.api.HostConnectApi;
|
||||||
import org.dromara.visor.module.infra.api.OperatorLogApi;
|
|
||||||
import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogQueryDTO;
|
|
||||||
import org.dromara.visor.module.terminal.convert.TerminalSftpLogConvert;
|
|
||||||
import org.dromara.visor.module.terminal.define.cache.TerminalCacheKeyDefine;
|
import org.dromara.visor.module.terminal.define.cache.TerminalCacheKeyDefine;
|
||||||
import org.dromara.visor.module.terminal.define.operator.TerminalOperatorType;
|
|
||||||
import org.dromara.visor.module.terminal.entity.dto.SftpGetContentCacheDTO;
|
import org.dromara.visor.module.terminal.entity.dto.SftpGetContentCacheDTO;
|
||||||
import org.dromara.visor.module.terminal.entity.dto.SftpSetContentCacheDTO;
|
import org.dromara.visor.module.terminal.entity.dto.SftpSetContentCacheDTO;
|
||||||
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalSftpLogQueryRequest;
|
|
||||||
import org.dromara.visor.module.terminal.entity.vo.TerminalSftpLogVO;
|
|
||||||
import org.dromara.visor.module.terminal.handler.transfer.manager.TerminalTransferManager;
|
import org.dromara.visor.module.terminal.handler.transfer.manager.TerminalTransferManager;
|
||||||
import org.dromara.visor.module.terminal.handler.transfer.session.DownloadSession;
|
import org.dromara.visor.module.terminal.handler.transfer.session.DownloadSession;
|
||||||
import org.dromara.visor.module.terminal.service.TerminalSftpService;
|
import org.dromara.visor.module.terminal.service.TerminalSftpService;
|
||||||
@@ -67,7 +55,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,54 +68,12 @@ import java.util.Optional;
|
|||||||
@Service
|
@Service
|
||||||
public class TerminalSftpServiceImpl implements TerminalSftpService {
|
public class TerminalSftpServiceImpl implements TerminalSftpService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private OperatorLogApi operatorLogApi;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private HostConnectApi hostConnectApi;
|
private HostConnectApi hostConnectApi;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private TerminalTransferManager terminalTransferManager;
|
private TerminalTransferManager terminalTransferManager;
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataGrid<TerminalSftpLogVO> getTerminalSftpLogPage(TerminalSftpLogQueryRequest request) {
|
|
||||||
// 查询
|
|
||||||
OperatorLogQueryDTO query = this.buildQueryInfo(request);
|
|
||||||
// 转换
|
|
||||||
return operatorLogApi.getOperatorLogPage(query)
|
|
||||||
.map(s -> {
|
|
||||||
JSONObject extra = JSON.parseObject(s.getExtra());
|
|
||||||
TerminalSftpLogVO vo = TerminalSftpLogConvert.MAPPER.to(s);
|
|
||||||
vo.setHostId(extra.getLong(ExtraFieldConst.HOST_ID));
|
|
||||||
vo.setHostName(extra.getString(ExtraFieldConst.HOST_NAME));
|
|
||||||
vo.setHostAddress(extra.getString(ExtraFieldConst.ADDRESS));
|
|
||||||
String[] paths = Optional.ofNullable(extra.getString(ExtraFieldConst.PATH))
|
|
||||||
.map(p -> p.split("\\|"))
|
|
||||||
.orElse(new String[0]);
|
|
||||||
vo.setPaths(paths);
|
|
||||||
vo.setExtra(extra);
|
|
||||||
return vo;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getTerminalSftpLogCount(TerminalSftpLogQueryRequest request) {
|
|
||||||
// 查询
|
|
||||||
OperatorLogQueryDTO query = this.buildQueryInfo(request);
|
|
||||||
// 转换
|
|
||||||
return operatorLogApi.getOperatorLogCount(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer deleteTerminalSftpLog(List<Long> idList) {
|
|
||||||
log.info("TerminalSftpService.deleteSftpLog start {}", JSON.toJSONString(idList));
|
|
||||||
Integer effect = operatorLogApi.deleteOperatorLog(idList);
|
|
||||||
log.info("TerminalSftpService.deleteSftpLog finish {}", effect);
|
|
||||||
// 设置日志参数
|
|
||||||
OperatorLogs.add(OperatorLogs.COUNT, effect);
|
|
||||||
return effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getFileContentByToken(String token, HttpServletResponse response) throws IOException {
|
public void getFileContentByToken(String token, HttpServletResponse response) throws IOException {
|
||||||
// 解析 token
|
// 解析 token
|
||||||
@@ -215,36 +160,4 @@ public class TerminalSftpServiceImpl implements TerminalSftpService {
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建查询对象
|
|
||||||
*
|
|
||||||
* @param request request
|
|
||||||
* @return query
|
|
||||||
*/
|
|
||||||
private OperatorLogQueryDTO buildQueryInfo(TerminalSftpLogQueryRequest request) {
|
|
||||||
Long hostId = request.getHostId();
|
|
||||||
String type = request.getType();
|
|
||||||
// 构建参数
|
|
||||||
OperatorLogQueryDTO query = OperatorLogQueryDTO.builder()
|
|
||||||
.userId(request.getUserId())
|
|
||||||
.result(request.getResult())
|
|
||||||
.startTimeStart(Arrays1.getIfPresent(request.getStartTimeRange(), 0))
|
|
||||||
.startTimeEnd(Arrays1.getIfPresent(request.getStartTimeRange(), 1))
|
|
||||||
.build();
|
|
||||||
query.setPage(request.getPage());
|
|
||||||
query.setLimit(request.getLimit());
|
|
||||||
query.setOrder(request.getOrder());
|
|
||||||
if (Strings.isBlank(type)) {
|
|
||||||
// 查询全部 SFTP 类型
|
|
||||||
query.setTypeList(TerminalOperatorType.SFTP_TYPES);
|
|
||||||
} else {
|
|
||||||
query.setType(type);
|
|
||||||
}
|
|
||||||
// 模糊查询
|
|
||||||
if (hostId != null) {
|
|
||||||
query.setExtra("\"hostId\": " + hostId + ",");
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dromara.visor.module.terminal.utils;
|
package org.dromara.visor.module.terminal.utils;
|
||||||
|
|
||||||
|
import cn.orionsec.kit.lang.constant.Letters;
|
||||||
import cn.orionsec.kit.lang.utils.io.FileType;
|
import cn.orionsec.kit.lang.utils.io.FileType;
|
||||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
import cn.orionsec.kit.lang.utils.io.Files1;
|
||||||
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
import cn.orionsec.kit.net.host.sftp.SftpFile;
|
||||||
@@ -41,6 +42,33 @@ public class SftpFileUtils {
|
|||||||
private SftpFileUtils() {
|
private SftpFileUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取移动目标路径
|
||||||
|
*
|
||||||
|
* @param source source
|
||||||
|
* @param target target
|
||||||
|
* @return absolute target
|
||||||
|
*/
|
||||||
|
public static String getAbsoluteTargetPath(String source, String target) {
|
||||||
|
if (target.charAt(0) == Letters.SLASH) {
|
||||||
|
// 绝对路径
|
||||||
|
return Files1.getPath(Files1.normalize(target));
|
||||||
|
} else {
|
||||||
|
// 相对路径
|
||||||
|
return Files1.getPath(Files1.normalize(Files1.getPath(source + "/../" + target)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分割文件路径
|
||||||
|
*
|
||||||
|
* @param path path
|
||||||
|
* @return paths
|
||||||
|
*/
|
||||||
|
public static String[] fromMultiPaths(String path) {
|
||||||
|
return path.split("\\|");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转为文件
|
* 转为文件
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=http://127.0.0.1:9200/orion-visor/api
|
|||||||
# websocket 路径
|
# websocket 路径
|
||||||
VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive
|
VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive
|
||||||
# 版本号
|
# 版本号
|
||||||
VITE_APP_VERSION=2.4.0
|
VITE_APP_VERSION=2.4.1
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=/orion-visor/api
|
|||||||
# websocket 路径
|
# websocket 路径
|
||||||
VITE_WS_BASE_URL=/orion-visor/keep-alive
|
VITE_WS_BASE_URL=/orion-visor/keep-alive
|
||||||
# 版本号
|
# 版本号
|
||||||
VITE_APP_VERSION=2.4.0
|
VITE_APP_VERSION=2.4.1
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "orion-visor-ui",
|
"name": "orion-visor-ui",
|
||||||
"description": "Orion Visor UI",
|
"description": "Orion Visor UI",
|
||||||
"version": "2.4.0",
|
"version": "2.4.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Jiahang Li",
|
"author": "Jiahang Li",
|
||||||
"license": "Apache 2.0",
|
"license": "Apache 2.0",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export interface HostRdpExtraSettingModel {
|
|||||||
authType: string;
|
authType: string;
|
||||||
identityId: number;
|
identityId: number;
|
||||||
lowBandwidthMode: boolean;
|
lowBandwidthMode: boolean;
|
||||||
|
initialProgram: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标签额外配置
|
// 标签额外配置
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export interface SystemSettingUpdateRequest {
|
|||||||
*/
|
*/
|
||||||
export interface AppInfoResponse {
|
export interface AppInfoResponse {
|
||||||
version: string;
|
version: string;
|
||||||
uuid: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
70
orion-visor-ui/src/api/terminal/terminal-file-log.ts
Normal file
70
orion-visor-ui/src/api/terminal/terminal-file-log.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import type { DataGrid, OrderDirection, Pagination } from '@/types/global';
|
||||||
|
import type { TableData } from '@arco-design/web-vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import qs from 'query-string';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 查询请求
|
||||||
|
*/
|
||||||
|
export interface TerminalFileLogQueryRequest extends Pagination, OrderDirection {
|
||||||
|
userId?: number;
|
||||||
|
hostId?: number;
|
||||||
|
type?: string;
|
||||||
|
result?: number;
|
||||||
|
startTimeRange?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 查询响应
|
||||||
|
*/
|
||||||
|
export interface TerminalFileLogQueryResponse extends TableData {
|
||||||
|
id: number;
|
||||||
|
userId: number;
|
||||||
|
username: number;
|
||||||
|
hostId: number;
|
||||||
|
hostName: string;
|
||||||
|
hostAddress: string;
|
||||||
|
address: string;
|
||||||
|
location: string;
|
||||||
|
userAgent: string;
|
||||||
|
paths: string[];
|
||||||
|
type: string;
|
||||||
|
result: string;
|
||||||
|
startTime: number;
|
||||||
|
extra: TerminalFileLogExtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端文件操作日志 拓展对象
|
||||||
|
*/
|
||||||
|
export interface TerminalFileLogExtra {
|
||||||
|
mod: number;
|
||||||
|
target: string;
|
||||||
|
maxCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询终端文件操作日志
|
||||||
|
*/
|
||||||
|
export function getTerminalFileLogPage(request: TerminalFileLogQueryRequest) {
|
||||||
|
return axios.post<DataGrid<TerminalFileLogQueryResponse>>('/terminal/terminal-file-log/query', request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询终端文件操作日志数量
|
||||||
|
*/
|
||||||
|
export function getTerminalFileLogCount(request: TerminalFileLogQueryRequest) {
|
||||||
|
return axios.post<number>('/terminal/terminal-file-log/count', request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除终端文件操作日志
|
||||||
|
*/
|
||||||
|
export function deleteTerminalFileLog(idList: Array<number>) {
|
||||||
|
return axios.delete('/terminal/terminal-file-log/delete', {
|
||||||
|
params: { idList },
|
||||||
|
paramsSerializer: params => {
|
||||||
|
return qs.stringify(params, { arrayFormat: 'comma' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,74 +1,5 @@
|
|||||||
import type { DataGrid, OrderDirection, Pagination } from '@/types/global';
|
|
||||||
import type { TableData } from '@arco-design/web-vue';
|
|
||||||
import { httpBaseUrl } from '@/utils/env';
|
import { httpBaseUrl } from '@/utils/env';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import qs from 'query-string';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SFTP 操作日志 查询请求
|
|
||||||
*/
|
|
||||||
export interface TerminalSftpLogQueryRequest extends Pagination, OrderDirection {
|
|
||||||
userId?: number;
|
|
||||||
hostId?: number;
|
|
||||||
type?: string;
|
|
||||||
result?: number;
|
|
||||||
startTimeRange?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SFTP 操作日志 查询响应
|
|
||||||
*/
|
|
||||||
export interface TerminalSftpLogQueryResponse extends TableData {
|
|
||||||
id: number;
|
|
||||||
userId: number;
|
|
||||||
username: number;
|
|
||||||
hostId: number;
|
|
||||||
hostName: string;
|
|
||||||
hostAddress: string;
|
|
||||||
address: string;
|
|
||||||
location: string;
|
|
||||||
userAgent: string;
|
|
||||||
paths: string[];
|
|
||||||
type: string;
|
|
||||||
result: string;
|
|
||||||
startTime: number;
|
|
||||||
extra: TerminalSftpLogExtra;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SFTP 操作日志 拓展对象
|
|
||||||
*/
|
|
||||||
export interface TerminalSftpLogExtra {
|
|
||||||
mod: number;
|
|
||||||
target: string;
|
|
||||||
maxCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询 SFTP 操作日志
|
|
||||||
*/
|
|
||||||
export function getTerminalSftpLogPage(request: TerminalSftpLogQueryRequest) {
|
|
||||||
return axios.post<DataGrid<TerminalSftpLogQueryResponse>>('/terminal/terminal-sftp/query-log', request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询 SFTP 操作日志数量
|
|
||||||
*/
|
|
||||||
export function getTerminalSftpLogCount(request: TerminalSftpLogQueryRequest) {
|
|
||||||
return axios.post<number>('/terminal/terminal-sftp/log-count', request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除 SFTP 操作日志
|
|
||||||
*/
|
|
||||||
export function deleteTerminalSftpLog(idList: Array<number>) {
|
|
||||||
return axios.delete('/terminal/terminal-sftp/delete-log', {
|
|
||||||
params: { idList },
|
|
||||||
paramsSerializer: params => {
|
|
||||||
return qs.stringify(params, { arrayFormat: 'comma' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 SFTP 文件内容
|
* 获取 SFTP 文件内容
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { MenuQueryResponse } from '@/api/system/menu';
|
import type { MenuQueryResponse } from '@/api/system/menu';
|
||||||
|
import type { AxiosResponse } from 'axios';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +36,9 @@ export interface UserUpdatePasswordResponse {
|
|||||||
* 获取用户聚合信息
|
* 获取用户聚合信息
|
||||||
*/
|
*/
|
||||||
export function getUserAggregateInfo() {
|
export function getUserAggregateInfo() {
|
||||||
return axios.get<UserAggregateResponse>('/infra/user-aggregate/user');
|
return axios.get<AxiosResponse<UserAggregateResponse>>('/infra/user-aggregate/user', {
|
||||||
|
unwrap: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -331,7 +331,7 @@
|
|||||||
// 查询未读消息
|
// 查询未读消息
|
||||||
pullHasUnreadMessage();
|
pullHasUnreadMessage();
|
||||||
// 注册未读消息轮询
|
// 注册未读消息轮询
|
||||||
messageIntervalId.value = setInterval(pullHasUnreadMessage, 30000);
|
messageIntervalId.value = window.setInterval(pullHasUnreadMessage, 30000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
// 等待一秒后先查询一下状态
|
// 等待一秒后先查询一下状态
|
||||||
setTimeout(pullExecStatus, 1000);
|
setTimeout(pullExecStatus, 1000);
|
||||||
// 注册状态轮询
|
// 注册状态轮询
|
||||||
pullIntervalId.value = setInterval(pullExecStatus, 5000);
|
pullIntervalId.value = window.setInterval(pullExecStatus, 5000);
|
||||||
}
|
}
|
||||||
// 打开日志
|
// 打开日志
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|||||||
@@ -172,11 +172,11 @@ export default class LogAppender implements ILogAppender {
|
|||||||
};
|
};
|
||||||
this.client.onmessage = this.processMessage.bind(this);
|
this.client.onmessage = this.processMessage.bind(this);
|
||||||
// 注册持久化
|
// 注册持久化
|
||||||
this.keepAliveTask = setInterval(() => {
|
this.keepAliveTask = window.setInterval(() => {
|
||||||
if (this.client?.readyState === WebSocket.OPEN) {
|
if (this.client?.readyState === WebSocket.OPEN) {
|
||||||
this.client?.send('p');
|
this.client?.send('p');
|
||||||
}
|
}
|
||||||
}, 15000) as unknown as number;
|
}, 15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开日志
|
// 打开日志
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const MessageStatus = {
|
|||||||
READ: 1,
|
READ: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MESSAGE_CONFIG_KEY = 'messageConfig';
|
export const MESSAGE_CONFIG_KEY = 'message-config';
|
||||||
|
|
||||||
// 查询数量
|
// 查询数量
|
||||||
export const messageLimit = 15;
|
export const messageLimit = 15;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { FileItem } from '@arco-design/web-vue';
|
|||||||
import type { IFileUploader, ResponseMessageBody } from './const';
|
import type { IFileUploader, ResponseMessageBody } from './const';
|
||||||
import { UploadOperatorType, UploadReceiverType } from './const';
|
import { UploadOperatorType, UploadReceiverType } from './const';
|
||||||
import { openFileUploadChannel } from '@/api/system/upload';
|
import { openFileUploadChannel } from '@/api/system/upload';
|
||||||
|
import { closeFileReader } from '@/utils/file';
|
||||||
|
|
||||||
// 512 KB
|
// 512 KB
|
||||||
export const PART_SIZE = 512 * 1024;
|
export const PART_SIZE = 512 * 1024;
|
||||||
@@ -81,13 +82,14 @@ export default class FileUploader implements IFileUploader {
|
|||||||
|
|
||||||
// 上传下一块数据
|
// 上传下一块数据
|
||||||
private async uploadNextPart() {
|
private async uploadNextPart() {
|
||||||
|
let reader = undefined as unknown as FileReader;
|
||||||
try {
|
try {
|
||||||
if (this.currentPart < this.totalPart) {
|
if (this.currentPart < this.totalPart) {
|
||||||
// 有下一个分片则上传
|
// 有下一个分片则上传
|
||||||
const start = this.currentPart++ * PART_SIZE;
|
const start = this.currentPart++ * PART_SIZE;
|
||||||
const end = Math.min(this.currentFile.size, start + PART_SIZE);
|
const end = Math.min(this.currentFile.size, start + PART_SIZE);
|
||||||
const chunk = this.currentFile.slice(start, end);
|
const chunk = this.currentFile.slice(start, end);
|
||||||
const reader = new FileReader();
|
reader = new FileReader();
|
||||||
// 读取数据
|
// 读取数据
|
||||||
const arrayBuffer = await new Promise((resolve, reject) => {
|
const arrayBuffer = await new Promise((resolve, reject) => {
|
||||||
reader.onload = () => resolve(reader.result);
|
reader.onload = () => resolve(reader.result);
|
||||||
@@ -107,11 +109,15 @@ export default class FileUploader implements IFileUploader {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 读取文件失败
|
// 发送读取文件失败
|
||||||
this.client?.send(JSON.stringify({
|
this.client?.send(JSON.stringify({
|
||||||
type: UploadOperatorType.ERROR,
|
type: UploadOperatorType.ERROR,
|
||||||
fileId: this.currentFileItem.uid,
|
fileId: this.currentFileItem.uid,
|
||||||
}));
|
}));
|
||||||
|
// 释放资源
|
||||||
|
if (reader) {
|
||||||
|
closeFileReader(reader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ const ASSET_AUDIT: AppRouteRecordRaw[] = [
|
|||||||
component: DEFAULT_LAYOUT,
|
component: DEFAULT_LAYOUT,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'connectLog',
|
name: 'terminalConnectLog',
|
||||||
path: '/audit/connect-log',
|
path: '/audit/terminal-connect-log',
|
||||||
component: () => import('@/views/asset-audit/connect-log/index.vue'),
|
component: () => import('@/views/asset-audit/terminal-connect-log/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'connectSession',
|
name: 'terminalConnectSession',
|
||||||
path: '/audit/connect-session',
|
path: '/audit/terminal-connect-session',
|
||||||
component: () => import('@/views/asset-audit/connect-session/index.vue'),
|
component: () => import('@/views/asset-audit/terminal-connect-session/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'sftpLog',
|
name: 'terminalFileLog',
|
||||||
path: '/audit/sftp-log',
|
path: '/audit/terminal-file-log',
|
||||||
component: () => import('@/views/asset-audit/sftp-log/index.vue'),
|
component: () => import('@/views/asset-audit/terminal-file-log/index.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import type {
|
import type {
|
||||||
TerminalInteractSetting,
|
|
||||||
TerminalPluginsSetting,
|
|
||||||
TerminalPreference,
|
TerminalPreference,
|
||||||
TerminalRdpActionBarSetting,
|
TerminalRdpActionBarSetting,
|
||||||
TerminalRdpGraphSetting,
|
TerminalRdpGraphSetting,
|
||||||
TerminalSessionSetting,
|
TerminalRdpSessionSetting,
|
||||||
TerminalShortcutSetting,
|
TerminalShortcutSetting,
|
||||||
TerminalSshActionBarSetting,
|
TerminalSshActionBarSetting,
|
||||||
TerminalSshDisplaySetting,
|
TerminalSshDisplaySetting,
|
||||||
|
TerminalSshInteractSetting,
|
||||||
|
TerminalSshPluginsSetting,
|
||||||
TerminalState
|
TerminalState
|
||||||
} from './types';
|
} from './types';
|
||||||
import type {
|
import type {
|
||||||
@@ -34,30 +34,30 @@ import { TerminalSessionTypes, TerminalTabs } from '@/views/terminal/types/const
|
|||||||
import TerminalTabManager from '@/views/terminal/service/tab/terminal-tab-manager';
|
import TerminalTabManager from '@/views/terminal/service/tab/terminal-tab-manager';
|
||||||
import TerminalPanelManager from '@/views/terminal/service/tab/terminal-panel-manager';
|
import TerminalPanelManager from '@/views/terminal/service/tab/terminal-panel-manager';
|
||||||
import TerminalSessionManager from '@/views/terminal/service/session/terminal-session-manager';
|
import TerminalSessionManager from '@/views/terminal/service/session/terminal-session-manager';
|
||||||
import SftpTransferManager from '@/views/terminal/service/transfer/sftp-transfer-manager';
|
import TerminalTransferManager from '@/views/terminal/service/transfer/terminal-transfer-manager';
|
||||||
|
|
||||||
// 终端偏好项
|
// 终端偏好项
|
||||||
export const TerminalPreferenceItem = {
|
export const TerminalPreferenceItem = {
|
||||||
// 新建连接类型
|
// 新建连接类型
|
||||||
NEW_CONNECTION_TYPE: 'newConnectionType',
|
NEW_CONNECTION_TYPE: 'newConnectionType',
|
||||||
// 终端主题
|
// ssh 主题
|
||||||
THEME: 'theme',
|
SSH_THEME: 'sshTheme',
|
||||||
// ssh 显示设置
|
// ssh 显示设置
|
||||||
SSH_DISPLAY_SETTING: 'sshDisplaySetting',
|
SSH_DISPLAY_SETTING: 'sshDisplaySetting',
|
||||||
// rdp 图形化设置
|
|
||||||
RDP_GRAPH_SETTING: 'rdpGraphSetting',
|
|
||||||
// ssh 操作栏设置
|
// ssh 操作栏设置
|
||||||
SSH_ACTION_BAR_SETTING: 'sshActionBarSetting',
|
SSH_ACTION_BAR_SETTING: 'sshActionBarSetting',
|
||||||
|
// ssh 右键菜单设置
|
||||||
|
SSH_RIGHT_MENU_SETTING: 'sshRightMenuSetting',
|
||||||
|
// ssh 交互设置
|
||||||
|
SSH_INTERACT_SETTING: 'sshInteractSetting',
|
||||||
|
// ssh 插件设置
|
||||||
|
SSH_PLUGINS_SETTING: 'sshPluginsSetting',
|
||||||
|
// rdp 图形化设置
|
||||||
|
RDP_GRAPH_SETTING: 'rdpGraphSetting',
|
||||||
// rdp 操作栏设置
|
// rdp 操作栏设置
|
||||||
RDP_ACTION_BAR_SETTING: 'rdpActionBarSetting',
|
RDP_ACTION_BAR_SETTING: 'rdpActionBarSetting',
|
||||||
// 右键菜单设置
|
|
||||||
RIGHT_MENU_SETTING: 'rightMenuSetting',
|
|
||||||
// 交互设置
|
|
||||||
INTERACT_SETTING: 'interactSetting',
|
|
||||||
// 插件设置
|
|
||||||
PLUGINS_SETTING: 'pluginsSetting',
|
|
||||||
// 会话设置
|
// 会话设置
|
||||||
SESSION_SETTING: 'sessionSetting',
|
RDP_SESSION_SETTING: 'rdpSessionSetting',
|
||||||
// 快捷键设置
|
// 快捷键设置
|
||||||
SHORTCUT_SETTING: 'shortcutSetting',
|
SHORTCUT_SETTING: 'shortcutSetting',
|
||||||
};
|
};
|
||||||
@@ -66,17 +66,17 @@ export default defineStore('terminal', {
|
|||||||
state: (): TerminalState => ({
|
state: (): TerminalState => ({
|
||||||
preference: {
|
preference: {
|
||||||
newConnectionType: 'group',
|
newConnectionType: 'group',
|
||||||
theme: {
|
sshTheme: {
|
||||||
schema: {} as TerminalThemeSchema
|
schema: {} as TerminalThemeSchema
|
||||||
} as TerminalTheme,
|
} as TerminalTheme,
|
||||||
sshDisplaySetting: {} as TerminalSshDisplaySetting,
|
sshDisplaySetting: {} as TerminalSshDisplaySetting,
|
||||||
rdpGraphSetting: {} as TerminalRdpGraphSetting,
|
|
||||||
sshActionBarSetting: {} as TerminalSshActionBarSetting,
|
sshActionBarSetting: {} as TerminalSshActionBarSetting,
|
||||||
|
sshRightMenuSetting: [],
|
||||||
|
sshInteractSetting: {} as TerminalSshInteractSetting,
|
||||||
|
sshPluginsSetting: {} as TerminalSshPluginsSetting,
|
||||||
|
rdpGraphSetting: {} as TerminalRdpGraphSetting,
|
||||||
|
rdpSessionSetting: {} as TerminalRdpSessionSetting,
|
||||||
rdpActionBarSetting: {} as TerminalRdpActionBarSetting,
|
rdpActionBarSetting: {} as TerminalRdpActionBarSetting,
|
||||||
rightMenuSetting: [],
|
|
||||||
interactSetting: {} as TerminalInteractSetting,
|
|
||||||
pluginsSetting: {} as TerminalPluginsSetting,
|
|
||||||
sessionSetting: {} as TerminalSessionSetting,
|
|
||||||
shortcutSetting: {
|
shortcutSetting: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
keys: []
|
keys: []
|
||||||
@@ -90,7 +90,7 @@ export default defineStore('terminal', {
|
|||||||
tabManager: new TerminalTabManager(),
|
tabManager: new TerminalTabManager(),
|
||||||
panelManager: new TerminalPanelManager(),
|
panelManager: new TerminalPanelManager(),
|
||||||
sessionManager: markRaw(new TerminalSessionManager()),
|
sessionManager: markRaw(new TerminalSessionManager()),
|
||||||
transferManager: new SftpTransferManager(),
|
transferManager: new TerminalTransferManager(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@@ -100,11 +100,11 @@ export default defineStore('terminal', {
|
|||||||
// 加载偏好
|
// 加载偏好
|
||||||
const { data } = await getPreference<TerminalPreference>('TERMINAL');
|
const { data } = await getPreference<TerminalPreference>('TERMINAL');
|
||||||
// theme 不存在则默认加载第一个
|
// theme 不存在则默认加载第一个
|
||||||
if (!data.theme?.name) {
|
if (!data.sshTheme?.name) {
|
||||||
const { data: themes } = await getTerminalThemes();
|
const { data: themes } = await getTerminalThemes();
|
||||||
data.theme = themes[0];
|
data.sshTheme = themes[0];
|
||||||
// 更新默认主题偏好
|
// 更新默认主题偏好
|
||||||
await this.updateTerminalPreference(TerminalPreferenceItem.THEME, data.theme);
|
await this.updateTerminalPreference(TerminalPreferenceItem.SSH_THEME, data.sshTheme);
|
||||||
}
|
}
|
||||||
// 移除禁用的快捷键
|
// 移除禁用的快捷键
|
||||||
if (data.shortcutSetting?.enabled) {
|
if (data.shortcutSetting?.enabled) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ISftpTransferManager, ITerminalPanelManager, ITerminalSessionManager, ITerminalTabManager, TerminalTheme } from '@/views/terminal/interfaces';
|
import type { ITerminalPanelManager, ITerminalSessionManager, ITerminalTabManager, ITerminalTransferManager, TerminalTheme } from '@/views/terminal/interfaces';
|
||||||
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
||||||
|
|
||||||
export interface TerminalState {
|
export interface TerminalState {
|
||||||
@@ -8,21 +8,21 @@ export interface TerminalState {
|
|||||||
tabManager: ITerminalTabManager;
|
tabManager: ITerminalTabManager;
|
||||||
panelManager: ITerminalPanelManager;
|
panelManager: ITerminalPanelManager;
|
||||||
sessionManager: ITerminalSessionManager;
|
sessionManager: ITerminalSessionManager;
|
||||||
transferManager: ISftpTransferManager;
|
transferManager: ITerminalTransferManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 终端配置
|
// 终端配置
|
||||||
export interface TerminalPreference {
|
export interface TerminalPreference {
|
||||||
newConnectionType: string;
|
newConnectionType: string;
|
||||||
theme: TerminalTheme;
|
sshTheme: TerminalTheme;
|
||||||
sshDisplaySetting: TerminalSshDisplaySetting;
|
sshDisplaySetting: TerminalSshDisplaySetting;
|
||||||
rdpGraphSetting: TerminalRdpGraphSetting;
|
|
||||||
sshActionBarSetting: TerminalSshActionBarSetting;
|
sshActionBarSetting: TerminalSshActionBarSetting;
|
||||||
|
sshRightMenuSetting: Array<string>,
|
||||||
|
sshInteractSetting: TerminalSshInteractSetting;
|
||||||
|
sshPluginsSetting: TerminalSshPluginsSetting;
|
||||||
|
rdpGraphSetting: TerminalRdpGraphSetting;
|
||||||
rdpActionBarSetting: TerminalRdpActionBarSetting;
|
rdpActionBarSetting: TerminalRdpActionBarSetting;
|
||||||
rightMenuSetting: Array<string>,
|
rdpSessionSetting: TerminalRdpSessionSetting;
|
||||||
interactSetting: TerminalInteractSetting;
|
|
||||||
pluginsSetting: TerminalPluginsSetting;
|
|
||||||
sessionSetting: TerminalSessionSetting;
|
|
||||||
shortcutSetting: TerminalShortcutSetting;
|
shortcutSetting: TerminalShortcutSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,13 +38,44 @@ export interface TerminalSshDisplaySetting {
|
|||||||
cursorBlink?: boolean;
|
cursorBlink?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSH 操作栏设置
|
||||||
|
export interface TerminalSshActionBarSetting {
|
||||||
|
connectStatus?: boolean;
|
||||||
|
share?: boolean;
|
||||||
|
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSH 插件设置
|
||||||
|
export interface TerminalSshPluginsSetting {
|
||||||
|
enableWeblinkPlugin: boolean;
|
||||||
|
enableWebglPlugin: boolean;
|
||||||
|
enableUnicodePlugin: boolean;
|
||||||
|
enableImagePlugin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSH 交互设置
|
||||||
|
export interface TerminalSshInteractSetting {
|
||||||
|
fastScrollModifier: boolean;
|
||||||
|
altClickMovesCursor: boolean;
|
||||||
|
rightClickSelectsWord: boolean;
|
||||||
|
selectionChangeCopy: boolean;
|
||||||
|
copyAutoTrim: boolean;
|
||||||
|
pasteAutoTrim: boolean;
|
||||||
|
rightClickPaste: boolean;
|
||||||
|
enableRightClickMenu: boolean;
|
||||||
|
enableBell: boolean;
|
||||||
|
wordSeparator: string;
|
||||||
|
terminalEmulationType: string;
|
||||||
|
scrollBackLine: number;
|
||||||
|
}
|
||||||
|
|
||||||
// RDP 图形化设置
|
// RDP 图形化设置
|
||||||
export interface TerminalRdpGraphSetting {
|
export interface TerminalRdpGraphSetting {
|
||||||
displaySize?: string;
|
displaySize?: string;
|
||||||
displayWidth?: number;
|
displayWidth?: number;
|
||||||
displayHeight?: number;
|
displayHeight?: number;
|
||||||
enableAudioInput?: boolean;
|
|
||||||
enableAudioOutput?: boolean;
|
|
||||||
colorDepth?: number;
|
colorDepth?: number;
|
||||||
forceLossless?: boolean;
|
forceLossless?: boolean;
|
||||||
enableWallpaper?: boolean;
|
enableWallpaper?: boolean;
|
||||||
@@ -56,13 +87,7 @@ export interface TerminalRdpGraphSetting {
|
|||||||
disableBitmapCaching?: boolean;
|
disableBitmapCaching?: boolean;
|
||||||
disableOffscreenCaching?: boolean;
|
disableOffscreenCaching?: boolean;
|
||||||
disableGlyphCaching?: boolean;
|
disableGlyphCaching?: boolean;
|
||||||
}
|
disableGfx?: boolean;
|
||||||
|
|
||||||
// SSH 操作栏设置
|
|
||||||
export interface TerminalSshActionBarSetting {
|
|
||||||
connectStatus?: boolean;
|
|
||||||
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RDP 操作栏设置
|
// RDP 操作栏设置
|
||||||
@@ -79,32 +104,11 @@ export interface TerminalRdpActionBarSetting {
|
|||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 交互设置
|
// RDP 会话设置
|
||||||
export interface TerminalInteractSetting {
|
export interface TerminalRdpSessionSetting {
|
||||||
fastScrollModifier: boolean;
|
enableAudioInput?: boolean;
|
||||||
altClickMovesCursor: boolean;
|
enableAudioOutput?: boolean;
|
||||||
rightClickSelectsWord: boolean;
|
driveMountMode?: string;
|
||||||
selectionChangeCopy: boolean;
|
|
||||||
copyAutoTrim: boolean;
|
|
||||||
pasteAutoTrim: boolean;
|
|
||||||
rightClickPaste: boolean;
|
|
||||||
enableRightClickMenu: boolean;
|
|
||||||
enableBell: boolean;
|
|
||||||
wordSeparator: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插件设置
|
|
||||||
export interface TerminalPluginsSetting {
|
|
||||||
enableWeblinkPlugin: boolean;
|
|
||||||
enableWebglPlugin: boolean;
|
|
||||||
enableUnicodePlugin: boolean;
|
|
||||||
enableImagePlugin: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 会话设置
|
|
||||||
export interface TerminalSessionSetting {
|
|
||||||
terminalEmulationType: string;
|
|
||||||
scrollBackLine: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 终端快捷键设置
|
// 终端快捷键设置
|
||||||
|
|||||||
@@ -8,6 +8,41 @@ import { removeRouteListener } from '@/utils/route-listener';
|
|||||||
import { getUserAggregateInfo } from '@/api/user/user-aggregate';
|
import { getUserAggregateInfo } from '@/api/user/user-aggregate';
|
||||||
import { useAppStore, useCacheStore, useMenuStore, useTabBarStore, useTipsStore } from '@/store';
|
import { useAppStore, useCacheStore, useMenuStore, useTabBarStore, useTipsStore } from '@/store';
|
||||||
|
|
||||||
|
const CHECK_APP_VERSION_KEY = 'check-app-version';
|
||||||
|
|
||||||
|
// 检查版本更新
|
||||||
|
const checkForVersionUpdate = (serverVersion: string) => {
|
||||||
|
try {
|
||||||
|
if (!serverVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const clientVersion = import.meta.env.VITE_APP_VERSION;
|
||||||
|
// 版本相同
|
||||||
|
if (serverVersion === clientVersion) {
|
||||||
|
localStorage.removeItem(CHECK_APP_VERSION_KEY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 版本不同
|
||||||
|
const lastCheck = localStorage.getItem(CHECK_APP_VERSION_KEY);
|
||||||
|
const lastCheckData = lastCheck ? JSON.parse(lastCheck) : null;
|
||||||
|
// 判断是否是同版本 或 距离上次提醒不超过 24 小时
|
||||||
|
if (lastCheckData?.version === serverVersion && Date.now() - (lastCheckData?.time || 0) < 24 * 60 * 60 * 1000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 提示用户更新
|
||||||
|
if (window.confirm('检测到新版本, 是否刷新页面以获取最新内容?')) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
// 更新 localStorage 记录
|
||||||
|
localStorage.setItem(CHECK_APP_VERSION_KEY, JSON.stringify({
|
||||||
|
version: serverVersion,
|
||||||
|
time: Date.now(),
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default defineStore('user', {
|
export default defineStore('user', {
|
||||||
state: (): UserState => ({
|
state: (): UserState => ({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@@ -32,7 +67,9 @@ export default defineStore('user', {
|
|||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
async getUserInfo() {
|
async getUserInfo() {
|
||||||
const { data } = await getUserAggregateInfo();
|
const { data: { data }, headers } = await getUserAggregateInfo();
|
||||||
|
// 检查版本更新
|
||||||
|
checkForVersionUpdate(headers?.['x-app-version']);
|
||||||
// 设置用户信息
|
// 设置用户信息
|
||||||
this.setUserInfo({
|
this.setUserInfo({
|
||||||
id: data.user.id,
|
id: data.user.id,
|
||||||
|
|||||||
@@ -41,6 +41,17 @@ export function readFileText(e: File, encoding = 'UTF-8'): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭 fileReader
|
||||||
|
export function closeFileReader(reader: FileReader) {
|
||||||
|
// 清理资源
|
||||||
|
if (reader.readyState === FileReader.LOADING) {
|
||||||
|
reader.abort();
|
||||||
|
}
|
||||||
|
reader.onload = null;
|
||||||
|
reader.onerror = null;
|
||||||
|
reader.onabort = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析路径类型
|
* 解析路径类型
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// 表名称
|
|
||||||
export const TableName = 'sftp-log';
|
|
||||||
|
|
||||||
// sftp 操作类型
|
|
||||||
export const SftpOperatorType = {
|
|
||||||
SFTP_MOVE: 'terminal:sftp-move',
|
|
||||||
SFTP_CHMOD: 'terminal:sftp-chmod',
|
|
||||||
};
|
|
||||||
|
|
||||||
// 最大展示数量
|
|
||||||
export const showPathMaxCount = 5;
|
|
||||||
|
|
||||||
// sftp 操作类型 字典项
|
|
||||||
export const sftpOperatorTypeKey = 'sftpOperatorType';
|
|
||||||
|
|
||||||
// sftp 操作结果 字典项
|
|
||||||
export const sftpOperatorResultKey = 'operatorLogResult';
|
|
||||||
|
|
||||||
// 加载的字典值
|
|
||||||
export const dictKeys = [sftpOperatorTypeKey, sftpOperatorResultKey];
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'connectLog'
|
name: 'terminalConnectLog'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<div class="table-left-bar-handle">
|
<div class="table-left-bar-handle">
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<div class="table-title">
|
<div class="table-title">
|
||||||
主机在线会话
|
终端在线会话
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'connectSession'
|
name: 'terminalConnectSession'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
import ConnectSessionTable from './components/connect-session-table.vue';
|
import ConnectSessionTable from './components/connect-session-table.vue';
|
||||||
|
|
||||||
const render = ref(false);
|
const render = ref(false);
|
||||||
const eventDrawer = ref();
|
|
||||||
|
|
||||||
// 加载字典配置
|
// 加载字典配置
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
@@ -24,14 +24,14 @@
|
|||||||
<a-form-item field="type" label="操作类型">
|
<a-form-item field="type" label="操作类型">
|
||||||
<a-select v-model="formModel.type"
|
<a-select v-model="formModel.type"
|
||||||
placeholder="请选择类型"
|
placeholder="请选择类型"
|
||||||
:options="toOptions(sftpOperatorTypeKey)"
|
:options="toOptions(terminalFileOperatorTypeKey)"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 执行结果 -->
|
<!-- 执行结果 -->
|
||||||
<a-form-item field="result" label="执行结果">
|
<a-form-item field="result" label="执行结果">
|
||||||
<a-select v-model="formModel.result"
|
<a-select v-model="formModel.result"
|
||||||
placeholder="请选择执行结果"
|
placeholder="请选择执行结果"
|
||||||
:options="toOptions(sftpOperatorResultKey)"
|
:options="toOptions(operatorResultKey)"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 开始时间 -->
|
<!-- 开始时间 -->
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<div class="table-left-bar-handle">
|
<div class="table-left-bar-handle">
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<div class="table-title">
|
<div class="table-title">
|
||||||
文件操作日志
|
终端文件日志
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧操作 -->
|
<!-- 右侧操作 -->
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
position="br"
|
position="br"
|
||||||
type="warning"
|
type="warning"
|
||||||
@ok="deleteSelectedRows">
|
@ok="deleteSelectedRows">
|
||||||
<a-button v-permission="['infra:operator-log:delete', 'terminal:terminal-sftp-log:management:delete']"
|
<a-button v-permission="['infra:operator-log:delete', 'terminal:terminal-file-log:management:delete']"
|
||||||
type="primary"
|
type="primary"
|
||||||
status="danger"
|
status="danger"
|
||||||
:disabled="selectedKeys.length === 0">
|
:disabled="selectedKeys.length === 0">
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<!-- 操作类型 -->
|
<!-- 操作类型 -->
|
||||||
<template #type="{ record }">
|
<template #type="{ record }">
|
||||||
<a-tag color="arcoblue">
|
<a-tag color="arcoblue">
|
||||||
{{ getDictValue(sftpOperatorTypeKey, record.type) }}
|
{{ getDictValue(terminalFileOperatorTypeKey, record.type) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<!-- 文件数量 -->
|
<!-- 文件数量 -->
|
||||||
@@ -127,11 +127,11 @@
|
|||||||
{{ path }}
|
{{ path }}
|
||||||
</span>
|
</span>
|
||||||
<!-- 移动目标路径 -->
|
<!-- 移动目标路径 -->
|
||||||
<span class="table-cell-sub-value" v-if="SftpOperatorType.SFTP_MOVE === record.type">
|
<span class="table-cell-sub-value" v-if="TerminalFileOperatorType.SFTP_MOVE === record.type">
|
||||||
移动到 {{ record.extra?.target }}
|
移动到 {{ record.extra?.target }}
|
||||||
</span>
|
</span>
|
||||||
<!-- 提权信息 -->
|
<!-- 提权信息 -->
|
||||||
<span class="table-cell-sub-value" v-if="SftpOperatorType.SFTP_CHMOD === record.type">
|
<span class="table-cell-sub-value" v-if="TerminalFileOperatorType.SFTP_CHMOD === record.type">
|
||||||
提权 {{ record.extra?.mod }} {{ permission10toString(record.extra?.mod as number) }}
|
提权 {{ record.extra?.mod }} {{ permission10toString(record.extra?.mod as number) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,8 +145,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<!-- 执行结果 -->
|
<!-- 执行结果 -->
|
||||||
<template #result="{ record }">
|
<template #result="{ record }">
|
||||||
<a-tag :color="getDictValue(sftpOperatorResultKey, record.result, 'color')">
|
<a-tag :color="getDictValue(operatorResultKey, record.result, 'color')">
|
||||||
{{ getDictValue(sftpOperatorResultKey, record.result) }}
|
{{ getDictValue(operatorResultKey, record.result) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<!-- 留痕地址 -->
|
<!-- 留痕地址 -->
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
position="left"
|
position="left"
|
||||||
type="warning"
|
type="warning"
|
||||||
@ok="deleteRow(record)">
|
@ok="deleteRow(record)">
|
||||||
<a-button v-permission="['infra:operator-log:delete', 'terminal:terminal-sftp-log:management:delete']"
|
<a-button v-permission="['infra:operator-log:delete', 'terminal:terminal-file-log:management:delete']"
|
||||||
type="text"
|
type="text"
|
||||||
size="mini"
|
size="mini"
|
||||||
status="danger">
|
status="danger">
|
||||||
@@ -184,15 +184,15 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'sftpLogTable'
|
name: 'fileLogTable'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { TerminalSftpLogQueryRequest, TerminalSftpLogQueryResponse } from '@/api/terminal/terminal-sftp';
|
import type { TerminalFileLogQueryRequest, TerminalFileLogQueryResponse } from '@/api/terminal/terminal-file-log';
|
||||||
import { reactive, ref, onMounted } from 'vue';
|
import { reactive, ref, onMounted } from 'vue';
|
||||||
import { getTerminalSftpLogPage, deleteTerminalSftpLog } from '@/api/terminal/terminal-sftp';
|
import { getTerminalFileLogPage, deleteTerminalFileLog } from '@/api/terminal/terminal-file-log';
|
||||||
import { TableName, sftpOperatorTypeKey, sftpOperatorResultKey, SftpOperatorType, showPathMaxCount } from '../types/const';
|
import { TableName, terminalFileOperatorTypeKey, operatorResultKey, TerminalFileOperatorType, showPathMaxCount } from '../types/const';
|
||||||
import { useTablePagination, useRowSelection, useTableColumns } from '@/hooks/table';
|
import { useTablePagination, useRowSelection, useTableColumns } from '@/hooks/table';
|
||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
@@ -212,9 +212,9 @@
|
|||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
const { toOptions, getDictValue } = useDictStore();
|
const { toOptions, getDictValue } = useDictStore();
|
||||||
|
|
||||||
const tableRenderData = ref<Array<TerminalSftpLogQueryResponse>>([]);
|
const tableRenderData = ref<Array<TerminalFileLogQueryResponse>>([]);
|
||||||
const selectedKeys = ref<Array<number>>([]);
|
const selectedKeys = ref<Array<number>>([]);
|
||||||
const formModel = reactive<TerminalSftpLogQueryRequest>({
|
const formModel = reactive<TerminalFileLogQueryRequest>({
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
hostId: undefined,
|
hostId: undefined,
|
||||||
type: undefined,
|
type: undefined,
|
||||||
@@ -223,11 +223,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const doFetchTableData = async (request: TerminalSftpLogQueryRequest) => {
|
const doFetchTableData = async (request: TerminalFileLogQueryRequest) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 查询
|
// 查询
|
||||||
const { data } = await getTerminalSftpLogPage(queryOrder.markOrderly(request));
|
const { data } = await getTerminalFileLogPage(queryOrder.markOrderly(request));
|
||||||
// 设置最大数量
|
// 设置最大数量
|
||||||
data.rows.forEach(s => {
|
data.rows.forEach(s => {
|
||||||
s.extra.maxCount = showPathMaxCount;
|
s.extra.maxCount = showPathMaxCount;
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 调用删除接口
|
// 调用删除接口
|
||||||
await deleteTerminalSftpLog(selectedKeys.value);
|
await deleteTerminalFileLog(selectedKeys.value);
|
||||||
Message.success(`成功删除 ${selectedKeys.value.length} 条数据`);
|
Message.success(`成功删除 ${selectedKeys.value.length} 条数据`);
|
||||||
selectedKeys.value = [];
|
selectedKeys.value = [];
|
||||||
// 重新加载
|
// 重新加载
|
||||||
@@ -265,11 +265,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 删除当前行
|
// 删除当前行
|
||||||
const deleteRow = async (record: TerminalSftpLogQueryResponse) => {
|
const deleteRow = async (record: TerminalFileLogQueryResponse) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 调用删除接口
|
// 调用删除接口
|
||||||
await deleteTerminalSftpLog([record.id]);
|
await deleteTerminalFileLog([record.id]);
|
||||||
Message.success('删除成功');
|
Message.success('删除成功');
|
||||||
selectedKeys.value = [];
|
selectedKeys.value = [];
|
||||||
// 重新加载
|
// 重新加载
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-container" v-if="render">
|
<div class="layout-container" v-if="render">
|
||||||
<!-- 列表-表格 -->
|
<!-- 列表-表格 -->
|
||||||
<sftp-log-table />
|
<file-log-table />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'sftpLog'
|
name: 'terminalFileLog'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
import { ref, onBeforeMount } from 'vue';
|
import { ref, onBeforeMount } from 'vue';
|
||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
import { dictKeys } from './types/const';
|
import { dictKeys } from './types/const';
|
||||||
import SftpLogTable from './components/sftp-log-table.vue';
|
import FileLogTable from './components/file-log-table.vue';
|
||||||
|
|
||||||
const render = ref(false);
|
const render = ref(false);
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// 表名称
|
||||||
|
export const TableName = 'file-log';
|
||||||
|
|
||||||
|
// 终端文件操作类型
|
||||||
|
export const TerminalFileOperatorType = {
|
||||||
|
SFTP_MOVE: 'terminal:sftp-move',
|
||||||
|
SFTP_CHMOD: 'terminal:sftp-chmod',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 最大展示数量
|
||||||
|
export const showPathMaxCount = 5;
|
||||||
|
|
||||||
|
// 终端文件操作类型 字典项
|
||||||
|
export const terminalFileOperatorTypeKey = 'terminalFileOperatorType';
|
||||||
|
|
||||||
|
// 操作结果 字典项
|
||||||
|
export const operatorResultKey = 'operatorLogResult';
|
||||||
|
|
||||||
|
// 加载的字典值
|
||||||
|
export const dictKeys = [terminalFileOperatorTypeKey, operatorResultKey];
|
||||||
@@ -30,7 +30,7 @@ const columns = [
|
|||||||
title: '操作类型',
|
title: '操作类型',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
slotName: 'type',
|
slotName: 'type',
|
||||||
width: 116,
|
width: 146,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
default: true,
|
default: true,
|
||||||
}, {
|
}, {
|
||||||
@@ -133,6 +133,7 @@
|
|||||||
|
|
||||||
// 更新主机信息
|
// 更新主机信息
|
||||||
const onUpdateHostInfo = (id: number) => {
|
const onUpdateHostInfo = (id: number) => {
|
||||||
|
title.value = '修改主机';
|
||||||
hostId.value = id;
|
hostId.value = id;
|
||||||
hostViewUpdated.value = true;
|
hostViewUpdated.value = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -194,11 +194,13 @@
|
|||||||
// 复制
|
// 复制
|
||||||
const { data } = await copyHost(formModel.value);
|
const { data } = await copyHost(formModel.value);
|
||||||
Message.success('复制成功');
|
Message.success('复制成功');
|
||||||
|
formModel.value.id = data;
|
||||||
emits('updated', data);
|
emits('updated', data);
|
||||||
} else if (!formModel.value.id) {
|
} else if (!formModel.value.id) {
|
||||||
// 新增
|
// 新增
|
||||||
const { data } = await createHost(formModel.value);
|
const { data } = await createHost(formModel.value);
|
||||||
Message.success('创建成功');
|
Message.success('创建成功');
|
||||||
|
formModel.value.id = data;
|
||||||
emits('updated', data);
|
emits('updated', data);
|
||||||
} else {
|
} else {
|
||||||
// 修改
|
// 修改
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
<!-- RDP版本 -->
|
<!-- RDP版本 -->
|
||||||
<a-form-item field="versionGt81"
|
<a-form-item field="versionGt81"
|
||||||
label="RDP版本"
|
label="RDP版本"
|
||||||
|
tooltip="RDP 8.1 及以上版本支持动态调整分辨率"
|
||||||
hide-asterisk>
|
hide-asterisk>
|
||||||
<a-switch v-model="formModel.versionGt81"
|
<a-switch v-model="formModel.versionGt81"
|
||||||
type="round"
|
type="round"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<!-- 跳转 -->
|
<!-- 跳转 -->
|
||||||
<span class="pointer span-blue"
|
<span class="pointer span-blue"
|
||||||
title="详情"
|
title="详情"
|
||||||
@click="router.push({ name: 'connectLog', query: { action: 'self' } })">
|
@click="router.push({ name: 'terminalConnectLog', query: { action: 'self' } })">
|
||||||
详情
|
详情
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
background: isDark.value ? '#354276' : '#E8F3FF',
|
background: isDark.value ? '#354276' : '#E8F3FF',
|
||||||
iconColor: isDark.value ? '#4A7FF7' : '#165DFF',
|
iconColor: isDark.value ? '#4A7FF7' : '#165DFF',
|
||||||
},
|
},
|
||||||
go: () => router.push({ name: 'connectLog', query: { action: 'self' } })
|
go: () => router.push({ name: 'terminalConnectLog', query: { action: 'self' } })
|
||||||
}, {
|
}, {
|
||||||
title: '今日批量执行次数',
|
title: '今日批量执行次数',
|
||||||
value: props.data.exec?.todayExecCommandCount || 0,
|
value: props.data.exec?.todayExecCommandCount || 0,
|
||||||
|
|||||||
@@ -278,7 +278,7 @@
|
|||||||
|
|
||||||
// 设置轮询状态
|
// 设置轮询状态
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
pullIntervalId.value = setInterval(pullTaskStatus, 5000);
|
pullIntervalId.value = window.setInterval(pullTaskStatus, 5000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 卸载状态查询
|
// 卸载状态查询
|
||||||
|
|||||||
@@ -429,7 +429,7 @@
|
|||||||
// 加载数据
|
// 加载数据
|
||||||
fetchTableData();
|
fetchTableData();
|
||||||
// 注册状态轮询
|
// 注册状态轮询
|
||||||
pullIntervalId.value = setInterval(pullExecStatus, 10000);
|
pullIntervalId.value = window.setInterval(pullExecStatus, 10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@@ -417,7 +417,7 @@
|
|||||||
// 加载数据
|
// 加载数据
|
||||||
fetchTableData();
|
fetchTableData();
|
||||||
// 注册状态轮询
|
// 注册状态轮询
|
||||||
pullIntervalId.value = setInterval(pullJobStatus, 10000);
|
pullIntervalId.value = window.setInterval(pullJobStatus, 10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user