🎉 优化 terminal 模块逻辑.

This commit is contained in:
lijiahangmax
2025-06-26 00:59:15 +08:00
parent 712b175179
commit 9d4c2aaeb4
206 changed files with 6612 additions and 1273 deletions

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-terminal</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>orion-visor-module-terminal-provider</artifactId>
<packaging>jar</packaging>
<description>项目终端模块</description>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<!-- common -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.api;
package org.dromara.visor.module.terminal.api;
import java.util.List;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.api;
package org.dromara.visor.module.terminal.api;
import java.util.List;

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-terminal</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>orion-visor-module-terminal-service</artifactId>
<packaging>jar</packaging>
<description>项目终端模块</description>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<!-- common -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-common</artifactId>
</dependency>
<!-- module common -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-common</artifactId>
<version>${revision}</version>
</dependency>
<!-- module provider -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-infra-provider</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-asset-provider</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-module-terminal-provider</artifactId>
<version>${revision}</version>
</dependency>
<!-- framework starter -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-biz-operator-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-desensitize</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-storage</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-test</artifactId>
</dependency>
<!-- framework starter -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-biz-operator-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-desensitize</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-storage</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-spring-boot-starter-job</artifactId>
</dependency>
<!-- guacd -->
<dependency>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-common</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 混淆插件 -->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -20,11 +20,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.api.impl;
package org.dromara.visor.module.terminal.api.impl;
import org.dromara.visor.module.terminal.api.CommandSnippetApi;
import org.dromara.visor.module.terminal.service.CommandSnippetService;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.module.asset.api.CommandSnippetApi;
import org.dromara.visor.module.asset.service.CommandSnippetService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

View File

@@ -20,11 +20,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.api.impl;
package org.dromara.visor.module.terminal.api.impl;
import org.dromara.visor.module.terminal.api.PathBookmarkApi;
import org.dromara.visor.module.terminal.service.PathBookmarkService;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.module.asset.api.PathBookmarkApi;
import org.dromara.visor.module.asset.service.PathBookmarkService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.configuration;
package org.dromara.visor.module.terminal.configuration;
import org.dromara.visor.module.asset.handler.host.exec.log.ExecLogTailHandler;
import org.dromara.visor.module.asset.handler.host.terminal.TerminalMessageDispatcher;
import org.dromara.visor.module.asset.handler.host.transfer.TransferMessageDispatcher;
import org.dromara.visor.module.asset.interceptor.ExecLogTailInterceptor;
import org.dromara.visor.module.asset.interceptor.TerminalAccessInterceptor;
import org.dromara.visor.module.asset.interceptor.TerminalTransferInterceptor;
import org.dromara.visor.module.terminal.handler.terminal.TerminalAccessRdpHandler;
import org.dromara.visor.module.terminal.handler.terminal.TerminalAccessSftpHandler;
import org.dromara.visor.module.terminal.handler.terminal.TerminalAccessSshHandler;
import org.dromara.visor.module.terminal.handler.transfer.TransferMessageDispatcher;
import org.dromara.visor.module.terminal.interceptor.TerminalAccessInterceptor;
import org.dromara.visor.module.terminal.interceptor.TerminalTransferInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
@@ -36,14 +36,14 @@ import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
import javax.annotation.Resource;
/**
* 资产模块 websocket 配置
* 终端模块 websocket 配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/28 11:39
*/
@Configuration
public class AssetWebSocketConfiguration implements WebSocketConfigurer {
public class TerminalWebSocketConfiguration implements WebSocketConfigurer {
@Value("${orion.websocket.prefix}")
private String prefix;
@@ -55,31 +55,35 @@ public class AssetWebSocketConfiguration implements WebSocketConfigurer {
private TerminalTransferInterceptor terminalTransferInterceptor;
@Resource
private ExecLogTailInterceptor execLogTailInterceptor;
private TerminalAccessSshHandler terminalAccessSshHandler;
@Resource
private TerminalMessageDispatcher terminalMessageDispatcher;
private TerminalAccessSftpHandler terminalAccessSftpHandler;
@Resource
private TerminalAccessRdpHandler terminalAccessRdpHandler;
@Resource
private TransferMessageDispatcher transferMessageDispatcher;
@Resource
private ExecLogTailHandler execLogTailHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 终端会话
registry.addHandler(terminalMessageDispatcher, prefix + "/terminal/access/{accessToken}")
// SSH 终端会话
registry.addHandler(terminalAccessSshHandler, prefix + "/terminal/access/ssh/{accessToken}")
.addInterceptors(terminalAccessInterceptor)
.setAllowedOrigins("*");
// SFTP 终端会话
registry.addHandler(terminalAccessSftpHandler, prefix + "/terminal/access/sftp/{accessToken}")
.addInterceptors(terminalAccessInterceptor)
.setAllowedOrigins("*");
// RDP 终端会话
registry.addHandler(terminalAccessRdpHandler, prefix + "/terminal/access/rdp/{accessToken}")
.addInterceptors(terminalAccessInterceptor)
.setAllowedOrigins("*");
// 文件传输
registry.addHandler(transferMessageDispatcher, prefix + "/terminal/transfer/{transferToken}")
.addInterceptors(terminalTransferInterceptor)
.setAllowedOrigins("*");
// 执行日志
registry.addHandler(execLogTailHandler, prefix + "/exec/log/{token}")
.addInterceptors(execLogTailInterceptor)
.setAllowedOrigins("*");
}
}

View File

@@ -20,19 +20,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
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.entity.request.snippet.CommandSnippetCreateRequest;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.CommandSnippetWrapperVO;
import org.dromara.visor.module.terminal.service.CommandSnippetService;
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.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.asset.entity.request.command.CommandSnippetCreateRequest;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.CommandSnippetWrapperVO;
import org.dromara.visor.module.asset.service.CommandSnippetService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -45,12 +45,12 @@ import javax.annotation.Resource;
* @version 1.0.0
* @since 2024-1-22 15:28
*/
@Tag(name = "asset - 命令片段服务")
@Tag(name = "terminal - 命令片段服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/command-snippet")
@RequestMapping("/terminal/command-snippet")
public class CommandSnippetController {
@Resource

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -29,11 +29,11 @@ import org.dromara.visor.common.validator.group.Id;
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.asset.entity.request.command.CommandSnippetGroupCreateRequest;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetGroupDeleteRequest;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetGroupUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.CommandSnippetGroupVO;
import org.dromara.visor.module.asset.service.CommandSnippetGroupService;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetGroupCreateRequest;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetGroupDeleteRequest;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetGroupUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.CommandSnippetGroupVO;
import org.dromara.visor.module.terminal.service.CommandSnippetGroupService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -47,12 +47,12 @@ import java.util.List;
* @version 1.0.0
* @since 2024-1-24 12:28
*/
@Tag(name = "asset - 命令片段分组服务")
@Tag(name = "terminal - 命令片段分组服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/command-snippet-group")
@RequestMapping("/terminal/command-snippet-group")
public class CommandSnippetGroupController {
@Resource

View File

@@ -20,17 +20,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
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.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkCreateRequest;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.PathBookmarkWrapperVO;
import org.dromara.visor.module.asset.service.PathBookmarkService;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkCreateRequest;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.PathBookmarkWrapperVO;
import org.dromara.visor.module.terminal.service.PathBookmarkService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -43,12 +43,12 @@ import javax.annotation.Resource;
* @version 1.0.6
* @since 2024-4-23 23:15
*/
@Tag(name = "asset - 路径标签服务")
@Tag(name = "terminal - 路径标签服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/path-bookmark")
@RequestMapping("/terminal/path-bookmark")
public class PathBookmarkController {
@Resource

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -29,11 +29,11 @@ import org.dromara.visor.common.validator.group.Id;
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.asset.entity.request.path.PathBookmarkGroupCreateRequest;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkGroupDeleteRequest;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkGroupUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.PathBookmarkGroupVO;
import org.dromara.visor.module.asset.service.PathBookmarkGroupService;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkGroupCreateRequest;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkGroupDeleteRequest;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkGroupUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.PathBookmarkGroupVO;
import org.dromara.visor.module.terminal.service.PathBookmarkGroupService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -47,12 +47,12 @@ import java.util.List;
* @version 1.0.0
* @since 2024-1-24 12:28
*/
@Tag(name = "asset - 路径标签分组服务")
@Tag(name = "terminal - 路径标签分组服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/path-bookmark-group")
@RequestMapping("/terminal/path-bookmark-group")
public class PathBookmarkGroupController {
@Resource

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
import io.swagger.v3.oas.annotations.Operation;
@@ -34,11 +34,11 @@ 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.DemoDisableApi;
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.define.operator.TerminalConnectLogOperatorType;
import org.dromara.visor.module.asset.entity.request.host.TerminalConnectLogClearRequest;
import org.dromara.visor.module.asset.entity.request.host.TerminalConnectLogQueryRequest;
import org.dromara.visor.module.asset.entity.vo.TerminalConnectLogVO;
import org.dromara.visor.module.asset.service.TerminalConnectLogService;
import org.dromara.visor.module.terminal.define.operator.TerminalConnectLogOperatorType;
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalConnectLogClearRequest;
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalConnectLogQueryRequest;
import org.dromara.visor.module.terminal.entity.vo.TerminalConnectLogVO;
import org.dromara.visor.module.terminal.service.TerminalConnectLogService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -54,12 +54,12 @@ import java.util.Set;
* @version 1.0.0
* @since 2023-12-26 22:09
*/
@Tag(name = "asset - 终端连接日志服务")
@Tag(name = "terminal - 终端连接日志服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/terminal-connect-log")
@RequestMapping("/terminal/terminal-connect-log")
public class TerminalConnectLogController {
@Resource
@@ -68,22 +68,22 @@ public class TerminalConnectLogController {
@IgnoreLog(IgnoreLogMode.RET)
@PostMapping("/query")
@Operation(summary = "分页查询终端连接日志")
@PreAuthorize("@ss.hasPermission('asset:terminal-connect-log:management:query')")
@PreAuthorize("@ss.hasPermission('terminal:terminal-connect-log:management:query')")
public DataGrid<TerminalConnectLogVO> getTerminalConnectLogPage(@Validated(Page.class) @RequestBody TerminalConnectLogQueryRequest request) {
return terminalConnectLogService.getTerminalConnectLogPage(request);
}
@PostMapping("/count")
@Operation(summary = "查询终端连接日志数量")
@PreAuthorize("@ss.hasPermission('asset:terminal-connect-log:management:query')")
@PreAuthorize("@ss.hasPermission('terminal:terminal-connect-log:management:query')")
public Long getTerminalConnectLogCount(@Validated @RequestBody TerminalConnectLogQueryRequest request) {
return terminalConnectLogService.getTerminalConnectLogCount(request);
}
@IgnoreLog(IgnoreLogMode.RET)
@PostMapping("/sessions")
@Operation(summary = "查询全部终端连接会话")
@PreAuthorize("@ss.hasPermission('asset:terminal-connect-session:management:query')")
@Operation(summary = "查询全部终端会话")
@PreAuthorize("@ss.hasPermission('terminal:terminal-connect-session:management:query')")
public List<TerminalConnectLogVO> getTerminalConnectSessions(@Validated @RequestBody TerminalConnectLogQueryRequest request) {
return terminalConnectLogService.getTerminalConnectSessions(request);
}
@@ -99,7 +99,7 @@ public class TerminalConnectLogController {
@DeleteMapping("/delete")
@Operation(summary = "删除终端连接日志")
@Parameter(name = "idList", description = "idList", required = true)
@PreAuthorize("@ss.hasPermission('asset:terminal-connect-log:management:delete')")
@PreAuthorize("@ss.hasPermission('terminal:terminal-connect-log:management:delete')")
public Integer deleteTerminalConnectLog(@RequestParam("idList") List<Long> idList) {
return terminalConnectLogService.deleteTerminalConnectLog(idList);
}
@@ -107,7 +107,7 @@ public class TerminalConnectLogController {
@OperatorLog(TerminalConnectLogOperatorType.CLEAR)
@PostMapping("/clear")
@Operation(summary = "清空终端连接日志")
@PreAuthorize("@ss.hasPermission('asset:terminal-connect-log:management:clear')")
@PreAuthorize("@ss.hasPermission('terminal:terminal-connect-log:management:clear')")
public Integer clearTerminalConnectLog(@Validated @RequestBody TerminalConnectLogClearRequest request) {
return terminalConnectLogService.clearTerminalConnectLog(request);
}
@@ -115,8 +115,8 @@ public class TerminalConnectLogController {
@DemoDisableApi
@OperatorLog(TerminalConnectLogOperatorType.FORCE_OFFLINE)
@PutMapping("/force-offline")
@Operation(summary = "强制断开终端连接")
@PreAuthorize("@ss.hasAnyPermission('asset:terminal-connect-log:management:force-offline', 'asset:terminal-connect-session:management:force-offline')")
@Operation(summary = "强制断开终端")
@PreAuthorize("@ss.hasAnyPermission('terminal:terminal-connect-log:management:force-offline', 'terminal:terminal-connect-session:management:force-offline')")
public Boolean forceOffline(@Validated(Id.class) @RequestBody TerminalConnectLogQueryRequest request) {
terminalConnectLogService.forceOffline(request);
return true;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -28,13 +28,12 @@ import lombok.extern.slf4j.Slf4j;
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.asset.entity.vo.TerminalThemeVO;
import org.dromara.visor.module.asset.service.TerminalService;
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalSessionAccessRequest;
import org.dromara.visor.module.terminal.entity.vo.TerminalThemeVO;
import org.dromara.visor.module.terminal.service.TerminalService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@@ -46,12 +45,12 @@ import java.util.List;
* @version 1.0.0
* @since 2023-9-20 11:55
*/
@Tag(name = "asset - 终端服务")
@Tag(name = "terminal - 终端服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/terminal")
@RequestMapping("/terminal/terminal")
public class TerminalController {
@Resource
@@ -64,16 +63,16 @@ public class TerminalController {
return terminalService.getTerminalThemes();
}
@GetMapping("/access")
@PostMapping("/access")
@Operation(summary = "获取终端 accessToken")
@PreAuthorize("@ss.hasPermission('asset:terminal:access')")
public String getTerminalAccessToken() {
return terminalService.getTerminalAccessToken();
@PreAuthorize("@ss.hasPermission('terminal:terminal:access')")
public String getTerminalAccessToken(@Validated @RequestBody TerminalSessionAccessRequest request) {
return terminalService.getTerminalAccessToken(request);
}
@GetMapping("/transfer")
@Operation(summary = "获取终端 transferToken")
@PreAuthorize("@ss.hasPermission('asset:terminal:access')")
@PreAuthorize("@ss.hasPermission('terminal:terminal:access')")
public String getTerminalTransferToken() {
return terminalService.getTerminalTransferToken();
}

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
import io.swagger.v3.oas.annotations.Operation;
@@ -33,10 +33,10 @@ 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.IgnoreWrapper;
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.entity.request.host.TerminalSftpLogQueryRequest;
import org.dromara.visor.module.asset.entity.vo.TerminalSftpLogVO;
import org.dromara.visor.module.asset.service.TerminalSftpService;
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.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -55,12 +55,12 @@ import java.util.List;
* @version 1.0.0
* @since 2023-12-26 22:09
*/
@Tag(name = "asset - SFTP 操作服务")
@Tag(name = "terminal - SFTP 操作服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/terminal-sftp")
@RequestMapping("/terminal/terminal-sftp")
public class TerminalSftpController {
@Resource
@@ -69,16 +69,24 @@ public class TerminalSftpController {
@IgnoreLog(IgnoreLogMode.RET)
@PostMapping("/query-log")
@Operation(summary = "分页查询 SFTP 操作日志")
@PreAuthorize("@ss.hasAnyPermission('infra:operator-log:query', 'asset:terminal-sftp-log:management:query')")
@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', 'asset:terminal-sftp-log:management:delete')")
@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);
}

View File

@@ -20,17 +20,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
package org.dromara.visor.module.terminal.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.entity.chart.PieChartData;
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.asset.service.AssetStatisticsService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.dromara.visor.module.terminal.entity.vo.TerminalWorkplaceStatisticsVO;
import org.dromara.visor.module.terminal.service.TerminalStatisticsService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -39,29 +38,28 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* asset - 统计服务
* terminal - 统计服务
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/12/23 15:56
* @since 2024/12/23 16:07
*/
@Tag(name = "asset - 统计服务")
@Tag(name = "terminal - 统计服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/statistics")
public class AssetStatisticsController {
@RequestMapping("/terminal/statistics")
public class TerminalStatisticsController {
@Resource
private AssetStatisticsService assetStatisticsService;
private TerminalStatisticsService terminalStatisticsService;
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/host-type-chart")
@Operation(summary = "查询主机类型图表")
@PreAuthorize("@ss.hasPermission('asset:statistics:query')")
public PieChartData getHostTypeChart() {
return assetStatisticsService.getHostTypeChart();
@GetMapping("/get-workplace")
@Operation(summary = "查询工作台统计信息")
public TerminalWorkplaceStatisticsVO getWorkplaceStatisticsData() {
return terminalStatisticsService.getWorkplaceStatisticsData();
}
}

View File

@@ -20,13 +20,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.domain.CommandSnippetDO;
import org.dromara.visor.module.asset.entity.dto.CommandSnippetCacheDTO;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetCreateRequest;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.CommandSnippetVO;
import org.dromara.visor.module.terminal.entity.domain.CommandSnippetDO;
import org.dromara.visor.module.terminal.entity.dto.CommandSnippetCacheDTO;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetCreateRequest;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.CommandSnippetVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetGroupCreateRequest;
import org.dromara.visor.module.asset.entity.request.command.CommandSnippetGroupUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.CommandSnippetGroupVO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupCreateDTO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupDTO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupRenameDTO;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetGroupCreateRequest;
import org.dromara.visor.module.terminal.entity.request.snippet.CommandSnippetGroupUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.CommandSnippetGroupVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -20,13 +20,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.domain.PathBookmarkDO;
import org.dromara.visor.module.asset.entity.dto.PathBookmarkCacheDTO;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkCreateRequest;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.PathBookmarkVO;
import org.dromara.visor.module.terminal.entity.domain.PathBookmarkDO;
import org.dromara.visor.module.terminal.entity.dto.PathBookmarkCacheDTO;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkCreateRequest;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.PathBookmarkVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkGroupCreateRequest;
import org.dromara.visor.module.asset.entity.request.path.PathBookmarkGroupUpdateRequest;
import org.dromara.visor.module.asset.entity.vo.PathBookmarkGroupVO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupCreateDTO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupDTO;
import org.dromara.visor.module.infra.entity.dto.data.DataGroupRenameDTO;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkGroupCreateRequest;
import org.dromara.visor.module.terminal.entity.request.path.PathBookmarkGroupUpdateRequest;
import org.dromara.visor.module.terminal.entity.vo.PathBookmarkGroupVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@@ -20,13 +20,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.domain.TerminalConnectLogDO;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import org.dromara.visor.module.asset.entity.request.host.TerminalConnectLogCreateRequest;
import org.dromara.visor.module.asset.entity.request.host.TerminalConnectLogQueryRequest;
import org.dromara.visor.module.asset.entity.vo.TerminalConnectLogVO;
import org.dromara.visor.module.terminal.entity.domain.TerminalConnectLogDO;
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalConnectLogCreateRequest;
import org.dromara.visor.module.terminal.entity.request.terminal.TerminalConnectLogQueryRequest;
import org.dromara.visor.module.terminal.entity.vo.TerminalConnectLogVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@@ -50,8 +49,6 @@ public interface TerminalConnectLogConvert {
TerminalConnectLogVO to(TerminalConnectLogDO domain);
TerminalConnectLogCreateRequest to(TerminalConnectDTO dto);
List<TerminalConnectLogVO> to(List<TerminalConnectLogDO> list);
}

View File

@@ -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.convert;
import org.dromara.visor.common.session.config.RdpConnectConfig;
import org.dromara.visor.common.session.config.SshConnectConfig;
import org.dromara.visor.module.terminal.handler.terminal.model.config.TerminalSessionRdpConfig;
import org.dromara.visor.module.terminal.handler.terminal.model.config.TerminalSessionSftpConfig;
import org.dromara.visor.module.terminal.handler.terminal.model.config.TerminalSessionSshConfig;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 终端会话 内部对象转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-12-26 22:09
*/
@Mapper
public interface TerminalSessionConvert {
TerminalSessionConvert MAPPER = Mappers.getMapper(TerminalSessionConvert.class);
TerminalSessionSshConfig toSsh(SshConnectConfig request);
TerminalSessionSftpConfig toSftp(SshConnectConfig request);
TerminalSessionRdpConfig toRdp(RdpConnectConfig domain);
}

View File

@@ -20,10 +20,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.convert;
package org.dromara.visor.module.terminal.convert;
import org.dromara.visor.module.asset.entity.vo.TerminalSftpLogVO;
import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogDTO;
import org.dromara.visor.module.terminal.entity.vo.TerminalSftpLogVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.dao;
package org.dromara.visor.module.terminal.dao;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.terminal.entity.domain.CommandSnippetDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.asset.entity.domain.CommandSnippetDO;
import java.util.List;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.dao;
package org.dromara.visor.module.terminal.dao;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.terminal.entity.domain.PathBookmarkDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.asset.entity.domain.PathBookmarkDO;
import java.util.List;

View File

@@ -20,13 +20,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.dao;
package org.dromara.visor.module.terminal.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.asset.entity.domain.TerminalConnectLogDO;
import org.dromara.visor.module.asset.entity.po.TerminalConnectLogCountPO;
import org.dromara.visor.module.terminal.entity.domain.TerminalConnectLogDO;
import org.dromara.visor.module.terminal.entity.po.TerminalConnectLogCountPO;
import java.util.Date;
import java.util.List;
@@ -73,4 +73,19 @@ public interface TerminalConnectLogDAO extends IMapper<TerminalConnectLogDO> {
@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
/**
* 通过 sessionId 查询
*
* @param sessionId sessionId
* @return row
*/
default TerminalConnectLogDO selectBySessionId(String sessionId) {
return this.of()
.createWrapper()
.eq(TerminalConnectLogDO::getSessionId, sessionId)
.orderByDesc(TerminalConnectLogDO::getId)
.then()
.getOne();
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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;
import cn.orionsec.kit.lang.define.thread.ExecutorBuilder;
import org.dromara.visor.common.constant.Const;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 终端线程池
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/1/3 11:21
*/
public interface TerminalThreadPools {
/**
* terminal 标准输出线程池
*/
ThreadPoolExecutor TERMINAL_STDOUT = ExecutorBuilder.create()
.namedThreadFactory("terminal-stdout-")
.corePoolSize(1)
.maxPoolSize(Integer.MAX_VALUE)
.keepAliveTime(Const.MS_S_60)
.workQueue(new SynchronousQueue<>())
.allowCoreThreadTimeout(true)
.build();
/**
* terminal 操作线程池
*/
ThreadPoolExecutor TERMINAL_OPERATOR = ExecutorBuilder.create()
.namedThreadFactory("terminal-operator-")
.corePoolSize(1)
.maxPoolSize(Integer.MAX_VALUE)
.keepAliveTime(Const.MS_S_60)
.workQueue(new SynchronousQueue<>())
.allowCoreThreadTimeout(true)
.build();
/**
* 终端异步保存线程池
*/
ThreadPoolExecutor TERMINAL_ASYNC_SAVER = ExecutorBuilder.create()
.namedThreadFactory("terminal-async-saver-")
.corePoolSize(1)
.maxPoolSize(1)
.workQueue(new LinkedBlockingQueue<>())
.build();
}

View File

@@ -20,12 +20,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.define.cache;
package org.dromara.visor.module.terminal.define.cache;
import org.dromara.visor.module.terminal.entity.dto.CommandSnippetCacheDTO;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine;
import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct;
import org.dromara.visor.module.asset.entity.dto.CommandSnippetCacheDTO;
import java.util.concurrent.TimeUnit;

View File

@@ -20,12 +20,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.define.cache;
package org.dromara.visor.module.terminal.define.cache;
import org.dromara.visor.module.terminal.entity.dto.PathBookmarkCacheDTO;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine;
import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct;
import org.dromara.visor.module.asset.entity.dto.PathBookmarkCacheDTO;
import java.util.concurrent.TimeUnit;

View File

@@ -20,15 +20,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.define.cache;
package org.dromara.visor.module.terminal.define.cache;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine;
import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct;
import org.dromara.visor.module.asset.entity.dto.SftpGetContentCacheDTO;
import org.dromara.visor.module.asset.entity.dto.SftpSetContentCacheDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalAccessDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalTransferDTO;
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.TerminalAccessDTO;
import org.dromara.visor.module.terminal.entity.dto.TerminalTransferDTO;
import java.util.concurrent.TimeUnit;

View File

@@ -0,0 +1,49 @@
/*
* 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.cache;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder;
import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine;
import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct;
import org.dromara.visor.module.terminal.entity.vo.TerminalWorkplaceStatisticsVO;
import java.util.concurrent.TimeUnit;
/**
* terminal 模块统计缓存 key
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/12/23 16:10
*/
public interface TerminalStatisticsCacheKeyDefine {
CacheKeyDefine WORKPLACE_DATA = new CacheKeyBuilder()
.key("data:statistics:terminal-workplace:{}:{}")
.desc("终端模块工作台统计 ${userId} ${time}")
.type(TerminalWorkplaceStatisticsVO.class)
.struct(RedisCacheStruct.STRING)
.timeout(10, TimeUnit.MINUTES)
.build();
}

View File

@@ -0,0 +1,75 @@
/*
* 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.message;
import org.dromara.visor.module.infra.define.SystemMessageDefine;
import org.dromara.visor.module.infra.enums.MessageClassifyEnum;
import lombok.Getter;
/**
* 上传任务 系统消息定义
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/5/14 17:23
*/
@Getter
public enum UploadMessageDefine implements SystemMessageDefine {
/**
* 上传任务部分失败
*/
UPLOAD_FAILED(MessageClassifyEnum.NOTICE,
"批量上传失败",
"您在 <sb>${time}</sb> 提交的上传任务中, 有部分主机文件上传失败。点击查看详情 <sb>#${id}</sb> >>>"),
;
UploadMessageDefine(MessageClassifyEnum classify, String title, String content) {
this.classify = classify;
this.type = this.name();
this.title = title;
this.content = content;
}
/**
* 消息分类
*/
private final MessageClassifyEnum classify;
/**
* 消息类型
*/
private final String type;
/**
* 标题
*/
private final String title;
/**
* 内容
*/
private final String content;
}

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.define.operator;
package org.dromara.visor.module.terminal.define.operator;
import org.dromara.visor.framework.biz.operator.log.core.annotation.Module;
import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes;
@@ -36,7 +36,7 @@ import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRi
* @version 1.0.0
* @since 2024/3/2 14:37
*/
@Module("asset:terminal-connect-log")
@Module("terminal:terminal-connect-log")
public class TerminalConnectLogOperatorType extends InitializingOperatorTypes {
public static final String DELETE = "terminal-connect-log:delete";

View File

@@ -20,17 +20,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.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.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;
import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel.*;
/**
* 终端 操作日志类型
*
@@ -38,7 +37,7 @@ import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRi
* @version 1.0.0
* @since 2023/10/10 17:30
*/
@Module("asset:terminal")
@Module("terminal:terminal")
public class TerminalOperatorType extends InitializingOperatorTypes {
public static final String CONNECT = "terminal:connect";
@@ -57,6 +56,12 @@ public class TerminalOperatorType extends InitializingOperatorTypes {
public static final String SFTP_CHMOD = "terminal:sftp-chmod";
public static final String SFTP_CHOWN = "terminal:sftp-chown";
public static final String SFTP_CHGRP = "terminal:sftp-chgrp";
public static final String SFTP_GET_CONTENT = "terminal:sftp-get-content";
public static final String SFTP_SET_CONTENT = "terminal:sftp-set-content";
public static final String SFTP_UPLOAD = "terminal:sftp-upload";
@@ -70,6 +75,9 @@ public class TerminalOperatorType extends InitializingOperatorTypes {
SFTP_REMOVE,
SFTP_TRUNCATE,
SFTP_CHMOD,
SFTP_CHOWN,
SFTP_CHGRP,
SFTP_GET_CONTENT,
SFTP_SET_CONTENT,
SFTP_UPLOAD,
SFTP_DOWNLOAD
@@ -78,17 +86,20 @@ public class TerminalOperatorType extends InitializingOperatorTypes {
@Override
public OperatorType[] types() {
return new OperatorType[]{
new OperatorType(L, CONNECT, "连接主机 ${connectType} <sb>${hostName}</sb>"),
new OperatorType(H, DELETE_SFTP_LOG, "删除 SFTP 操作日志 <sb>${count}</sb> 条"),
new OperatorType(L, SFTP_MKDIR, "创建文件夹 ${hostName} <sb>${path}</sb>"),
new OperatorType(L, SFTP_TOUCH, "创建文件 ${hostName} <sb>${path}</sb>"),
new OperatorType(M, SFTP_MOVE, "移动文件 ${hostName} <sb>${path}</sb> 至 <sb>${target}</sb>"),
new OperatorType(H, SFTP_REMOVE, "删除文件 ${hostName} <sb>${path}</sb>"),
new OperatorType(H, SFTP_TRUNCATE, "截断文件 ${hostName} <sb>${path}</sb>"),
new OperatorType(M, SFTP_CHMOD, "文件提权 ${hostName} <sb>${path}</sb> <sb>${mod}</sb>"),
new OperatorType(M, SFTP_SET_CONTENT, "修改文件内容 ${hostName} <sb>${path}</sb>"),
new OperatorType(M, SFTP_UPLOAD, "上传文件 ${hostName} <sb>${path}</sb>"),
new OperatorType(M, SFTP_DOWNLOAD, "下载文件 ${hostName} <sb>${path}</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_TOUCH, "创建文件 ${hostName} <sb>${path}</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_TRUNCATE, "截断文件 ${hostName} <sb>${path}</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_CHGRP, "修改文件分组 ${hostName} <sb>${path}</sb> <sb>${id}</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_UPLOAD, "上传文件 ${hostName} <sb>${path}</sb>"),
new OperatorType(OperatorRiskLevel.M, SFTP_DOWNLOAD, "下载文件 ${hostName} <sb>${path}</sb>"),
};
}

View File

@@ -20,8 +20,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.domain;
package org.dromara.visor.module.terminal.entity.domain;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,7 +31,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
/**
* 命令片段 实体对象

View File

@@ -20,8 +20,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.domain;
package org.dromara.visor.module.terminal.entity.domain;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,7 +31,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
/**
* 路径标签 实体对象

View File

@@ -20,8 +20,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.domain;
package org.dromara.visor.module.terminal.entity.domain;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,7 +31,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
import java.util.Date;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import cn.orionsec.kit.lang.define.cache.key.model.LongCacheIdModel;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import cn.orionsec.kit.lang.define.cache.key.model.LongCacheIdModel;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,14 +20,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject;
import java.util.Map;
/**
* 终端访问参数
@@ -40,7 +41,6 @@ import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DesensitizeObject
@Schema(name = "TerminalAccessDTO", description = "终端访问参数")
public class TerminalAccessDTO {
@@ -50,4 +50,16 @@ public class TerminalAccessDTO {
@Schema(description = "username")
private String username;
@Schema(description = "nickname")
private String nickname;
@Schema(description = "hostId")
private Long hostId;
@Schema(description = "连接类型")
private String connectType;
@Schema(description = "额外信息")
private Map<String, Object> extra;
}

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
@@ -54,8 +54,8 @@ public class TerminalConnectLogExtraDTO {
@Schema(description = "traceId")
private String traceId;
@Schema(description = "channelId")
private String channelId;
@Schema(description = "channel")
private String channel;
@Schema(description = "sessionId")
private String sessionId;

View File

@@ -20,14 +20,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.dto;
package org.dromara.visor.module.terminal.entity.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject;
/**
* 终端传输参数
@@ -40,7 +39,6 @@ import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DesensitizeObject
@Schema(name = "TerminalTransferDTO", description = "终端传输参数")
public class TerminalTransferDTO {
@@ -50,4 +48,7 @@ public class TerminalTransferDTO {
@Schema(description = "username")
private String username;
@Schema(description = "nickname")
private String nickname;
}

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.po;
package org.dromara.visor.module.terminal.entity.po;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.path;
package org.dromara.visor.module.terminal.entity.request.path;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.path;
package org.dromara.visor.module.terminal.entity.request.path;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.path;
package org.dromara.visor.module.terminal.entity.request.path;
import org.dromara.visor.common.validator.group.Id;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.common.validator.group.Id;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.path;
package org.dromara.visor.module.terminal.entity.request.path;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.path;
package org.dromara.visor.module.terminal.entity.request.path;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.command;
package org.dromara.visor.module.terminal.entity.request.snippet;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.command;
package org.dromara.visor.module.terminal.entity.request.snippet;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.command;
package org.dromara.visor.module.terminal.entity.request.snippet;
import org.dromara.visor.common.validator.group.Id;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.common.validator.group.Id;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.command;
package org.dromara.visor.module.terminal.entity.request.snippet;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.command;
package org.dromara.visor.module.terminal.entity.request.snippet;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,12 +20,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
package org.dromara.visor.module.terminal.entity.request.terminal;
import org.dromara.visor.common.entity.DataClearRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.visor.common.entity.DataClearRequest;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
package org.dromara.visor.module.terminal.entity.request.terminal;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,13 +20,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
package org.dromara.visor.module.terminal.entity.request.terminal;
import org.dromara.visor.common.entity.BaseQueryRequest;
import org.dromara.visor.common.validator.group.Id;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.dromara.visor.common.entity.BaseQueryRequest;
import org.dromara.visor.common.validator.group.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
package org.dromara.visor.module.terminal.entity.request.terminal;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
@@ -30,28 +30,31 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Map;
/**
* 主机 更新配置请求对象
* 终端会话访问请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-13 14:31
* @since 2023-12-26 22:09
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostUpdateConfigRequest", description = "主机 更新配置请求对象")
public class HostUpdateConfigRequest implements Serializable {
@Schema(name = "TerminalSessionAccessRequest", description = "终端会话访问请求对象")
public class TerminalSessionAccessRequest {
@NotNull
@Schema(description = "id")
private Long id;
@Schema(description = "主机id")
private Long hostId;
@NotBlank
@Schema(description = "配置详情")
private String config;
@Schema(description = "连接类型")
private String connectType;
@Schema(description = "额外信息")
private Map<String, Object> extra;
}

View File

@@ -20,12 +20,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
package org.dromara.visor.module.terminal.entity.request.terminal;
import org.dromara.visor.common.entity.BaseQueryRequest;
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;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import org.dromara.visor.module.terminal.entity.dto.TerminalConnectLogExtraDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectLogExtraDTO;
import java.io.Serializable;
import java.util.Date;
@@ -69,12 +69,12 @@ public class TerminalConnectLogVO implements Serializable {
@Schema(description = "类型")
private String type;
@Schema(description = "状态")
private String status;
@Schema(description = "sessionId")
private String sessionId;
@Schema(description = "状态")
private String status;
@Schema(description = "开始时间")
private Date startTime;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.vo;
package org.dromara.visor.module.terminal.entity.vo;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@@ -0,0 +1,60 @@
/*
* 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 org.dromara.visor.common.entity.chart.LineSingleChartData;
import java.util.List;
/**
* 终端模块工作台统计响应
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/12/26 15:32
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "TerminalWorkplaceStatisticsVO", description = "终端模块工作台统计响应")
public class TerminalWorkplaceStatisticsVO {
@Schema(description = "今日连接终端次数")
private Integer todayTerminalConnectCount;
@Schema(description = "7日连接终端次数")
private Integer weekTerminalConnectCount;
@Schema(description = "连接终端次数图表")
private LineSingleChartData terminalConnectChart;
@Schema(description = "连接终端记录")
private List<TerminalConnectLogVO> terminalConnectList;
}

View File

@@ -20,9 +20,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.enums;
package org.dromara.visor.module.terminal.enums;
import cn.orionsec.kit.lang.utils.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@@ -33,30 +35,34 @@ import java.util.List;
* @version 1.0.0
* @since 2023/12/26 22:27
*/
@Getter
@AllArgsConstructor
public enum TerminalConnectStatusEnum {
/**
* 连接中
*/
CONNECTING,
CONNECTING("连接中"),
/**
* 完成
*/
COMPLETE,
COMPLETE("完成"),
/**
* 失败
*/
FAILED,
FAILED("失败"),
/**
* 强制下线
*/
FORCE_OFFLINE,
FORCE_OFFLINE("强制下线"),
;
private final String label;
public static final List<String> FINISH_STATUS_LIST = Lists.of(COMPLETE.name(), FAILED.name(), FORCE_OFFLINE.name());
public static TerminalConnectStatusEnum of(String type) {

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.enums;
package org.dromara.visor.module.terminal.enums;
/**
* 终端连接类型
@@ -41,6 +41,16 @@ public enum TerminalConnectTypeEnum {
*/
SFTP,
/**
* rdp
*/
RDP,
/**
* vnc
*/
// VNC,
;
public static TerminalConnectTypeEnum of(String type) {

View File

@@ -0,0 +1,57 @@
/*
* 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.guacd;
import lombok.Getter;
import org.apache.guacamole.net.AbstractGuacamoleTunnel;
import org.apache.guacamole.net.GuacamoleSocket;
import java.util.UUID;
/**
* 自定义 guacamole 隧道
* <p>
* 为了保证与 websocket 的 uuid 一致
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/4/1 0:23
*/
public class CustomGuacamoleTunnel extends AbstractGuacamoleTunnel {
private final UUID uuid;
@Getter
private final GuacamoleSocket socket;
public CustomGuacamoleTunnel(String uuid, GuacamoleSocket socket) {
this.uuid = UUID.fromString(uuid);
this.socket = socket;
}
@Override
public UUID getUUID() {
return uuid;
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.guacd;
import lombok.Getter;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.protocol.GuacamoleStatus;
/**
* guacd code 异常
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/31 16:13
*/
public class GuacdException extends RuntimeException {
@Getter
private final int code;
public GuacdException(GuacamoleException ex) {
this(ex.getMessage(), ex);
}
public GuacdException(String message, GuacamoleException ex) {
super(message, ex);
this.code = ex.getStatus().getGuacamoleStatusCode();
}
/**
* 获取 guacd 状态码
*
* @return status
*/
public GuacamoleStatus getStatus() {
return GuacamoleStatus.fromGuacamoleStatusCode(code);
}
}

View File

@@ -0,0 +1,309 @@
/*
* 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.guacd;
import cn.orionsec.kit.lang.support.Attempt;
import cn.orionsec.kit.lang.utils.Objects1;
import cn.orionsec.kit.lang.utils.Valid;
import cn.orionsec.kit.lang.utils.collect.Lists;
import cn.orionsec.kit.lang.utils.io.Streams;
import lombok.Getter;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.GuacamoleSocket;
import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.InetGuacamoleSocket;
import org.apache.guacamole.protocol.*;
import org.dromara.visor.common.constant.Const;
import org.dromara.visor.module.terminal.handler.guacd.constant.GuacdConst;
import org.dromara.visor.module.terminal.handler.guacd.constant.GuacdProtocol;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* guacd tunnel
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/31 0:20
*/
public class GuacdTunnel implements IGuacdTunnel {
private final String uuid;
private final String serverAddress;
private final int serverPort;
@Getter
private final GuacamoleConfiguration serverConfig;
@Getter
private final GuacamoleClientInformation clientConfig;
@Getter
private GuacamoleSocket socket;
@Getter
private GuacamoleTunnel tunnel;
private Runnable callback;
private volatile boolean closed;
private Attempt.UncheckedConsumer<GuacamoleReader, GuacamoleException> streamHandler;
public GuacdTunnel(GuacdProtocol protocol, String uuid, String serverAddress, int serverPort) {
this.uuid = uuid;
this.serverAddress = serverAddress;
this.serverPort = serverPort;
this.serverConfig = new GuacamoleConfiguration();
this.clientConfig = new GuacamoleClientInformation();
serverConfig.setProtocol(protocol.getValue());
clientConfig.setName(uuid);
}
@Override
public void connect() throws GuacdException {
try {
// TODO 端口转发
this.socket = new ConfiguredGuacamoleSocket(new InetGuacamoleSocket(serverAddress, serverPort), serverConfig, clientConfig);
this.tunnel = new CustomGuacamoleTunnel(uuid, socket);
} catch (GuacamoleException e) {
throw new GuacdException("connect guacd tunnel error", e);
}
}
@Override
public void run() {
this.exec();
}
@Override
public void exec() throws GuacdException {
Valid.notNull(socket, "server is null");
Valid.notNull(streamHandler, "streamHandler is null");
// 读取
try {
GuacamoleReader reader = tunnel.acquireReader();
streamHandler.accept(reader);
} catch (GuacamoleException e) {
throw new GuacdException(e);
} finally {
// 释放
tunnel.releaseReader();
}
// 回调
if (callback != null) {
try {
callback.run();
} catch (Exception e) {
// ignored
}
}
// 释放资源
Streams.close(this);
}
@Override
public void write(String data) throws GuacdException {
this.write(data.toCharArray());
}
@Override
public void write(byte[] data) throws GuacdException {
this.write(new String(data));
}
@Override
public void write(char[] data) throws GuacdException {
this.write(s -> s.write(data));
}
@Override
public void writeInstruction(String opcode, String... args) throws GuacdException {
this.write(s -> s.writeInstruction(new GuacamoleInstruction(opcode, args)));
}
@Override
public void writeInstruction(String opcode, List<String> args) throws GuacdException {
this.write(s -> s.writeInstruction(new GuacamoleInstruction(opcode, args)));
}
/**
* 写入
*
* @param writer writer
* @throws GuacdException GuacdCodeException
*/
private void write(Attempt.UncheckedConsumer<GuacamoleWriter, GuacamoleException> writer) throws GuacdException {
try {
// 创建过滤写入器
GuacamoleWriter write = new FilteredGuacamoleWriter(tunnel.acquireWriter(), s -> {
// 过滤交互指令
if (GuacamoleTunnel.INTERNAL_DATA_OPCODE.equals(s.getOpcode())) {
return null;
}
return s;
});
// 写入
writer.accept(write);
} catch (GuacamoleException e) {
throw new GuacdException(e);
} finally {
// 释放
tunnel.releaseWriter();
}
}
@Override
public void remote(String address, int port) {
this.setParameter(GuacdConst.HOSTNAME, address);
this.setParameter(GuacdConst.PORT, port);
}
@Override
public void auth(String username, String password) {
this.setParameter(GuacdConst.USERNAME, username);
this.setParameter(GuacdConst.PASSWORD, password);
}
@Override
public void size(int width, int height, int dpi) {
clientConfig.setOptimalScreenWidth(width);
clientConfig.setOptimalScreenHeight(height);
clientConfig.setOptimalResolution(dpi);
this.setParameter(GuacdConst.WIDTH, width);
this.setParameter(GuacdConst.HEIGHT, height);
this.setParameter(GuacdConst.DPI, dpi);
}
@Override
public void timezone(String timezone) {
clientConfig.setTimezone(timezone);
this.setParameter(GuacdConst.TIMEZONE, timezone);
}
@Override
public void setParameter(String key, Object value) {
if (value != null) {
serverConfig.setParameter(key, Objects1.toString(value));
} else {
serverConfig.unsetParameter(key);
}
}
@Override
public void setParameter(Map<String, Object> params) {
params.forEach(this::setParameter);
}
@Override
public void setAudioMimeTypes(List<String> mimeTypes) {
if (Lists.isEmpty(mimeTypes)) {
return;
}
clientConfig.getAudioMimetypes().addAll(mimeTypes);
}
@Override
public void setVideoMimeTypes(List<String> mimeTypes) {
if (Lists.isEmpty(mimeTypes)) {
return;
}
clientConfig.getVideoMimetypes().addAll(mimeTypes);
}
@Override
public void setImageMimeTypes(List<String> mimeTypes) {
if (Lists.isEmpty(mimeTypes)) {
return;
}
clientConfig.getImageMimetypes().addAll(mimeTypes);
}
@Override
public void setConnectionId(String connectionId) {
serverConfig.setConnectionID(connectionId);
}
@Override
public void callback(Runnable callback) {
this.callback = callback;
}
@Override
public void transfer(Consumer<String> out) {
this.streamHandler = (reader) -> {
// 读取消息
StringBuilder buffer = new StringBuilder(Const.BUFFER_KB_8);
char[] readMessage;
while ((readMessage = reader.read()) != null && !closed) {
// 插入消息
buffer.append(readMessage);
// 响应消息
if (!reader.available() || buffer.length() >= Const.BUFFER_KB_8) {
out.accept(buffer.toString());
buffer.setLength(0);
}
}
};
}
@Override
public void streamHandler(Attempt.UncheckedConsumer<GuacamoleReader, GuacamoleException> streamHandler) {
this.streamHandler = streamHandler;
}
@Override
public String getConnectionId() {
return serverConfig.getConnectionID();
}
@Override
public boolean isOpen() {
if (tunnel != null) {
return tunnel.isOpen();
}
return false;
}
@Override
public void close() {
if (closed) {
return;
}
this.closed = true;
if (tunnel != null) {
try {
tunnel.close();
} catch (Exception e) {
// ignored
}
}
}
}

View File

@@ -0,0 +1,217 @@
/*
* 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.guacd;
import cn.orionsec.kit.lang.able.Executable;
import cn.orionsec.kit.lang.able.SafeCloseable;
import cn.orionsec.kit.lang.support.Attempt;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.protocol.GuacamoleClientInformation;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* guacd tunnel 定义
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/31 0:51
*/
public interface IGuacdTunnel extends Runnable, Executable, SafeCloseable {
/**
* 设置主机地址
*
* @param address address
* @param port port
*/
void remote(String address, int port);
/**
* 设置远程连接认证
*
* @param username username
* @param password password
*/
void auth(String username, String password);
/**
* 大小
*
* @param width width
* @param height height
* @param dpi dpi
*/
void size(int width, int height, int dpi);
/**
* 设置时区
*
* @param timezone 时区
*/
void timezone(String timezone);
/**
* 设置参数
*
* @param key key
* @param value value
*/
void setParameter(String key, Object value);
/**
* 设置参数
*
* @param params params
*/
void setParameter(Map<String, Object> params);
/**
* 设置音频类型
*
* @param mimeTypes mimeTypes
*/
void setAudioMimeTypes(List<String> mimeTypes);
/**
* 设置视频类型
*
* @param mimeTypes mimeTypes
*/
void setVideoMimeTypes(List<String> mimeTypes);
/**
* 设置图像类型
*
* @param mimeTypes mimeTypes
*/
void setImageMimeTypes(List<String> mimeTypes);
/**
* 设置连接的id
*
* @param connectionId connectionId
*/
void setConnectionId(String connectionId);
/**
* 设置回调
*
* @param callback callback
*/
void callback(Runnable callback);
/**
* 设置传输
*/
void transfer(Consumer<String> out);
/**
* 设置 streamHandler
*
* @param streamHandler streamHandler
*/
void streamHandler(Attempt.UncheckedConsumer<GuacamoleReader, GuacamoleException> streamHandler);
/**
* 连接
*
* @throws GuacdException GuacdCodeException
*/
void connect() throws GuacdException;
/**
* 输入命令
*
* @param data data
* @throws GuacdException GuacdCodeException
*/
void write(String data) throws GuacdException;
/**
* 输入命令
*
* @param data data
* @throws GuacdException GuacdCodeException
*/
void write(byte[] data) throws GuacdException;
/**
* 输入命令
*
* @param data data
* @throws GuacdException GuacdCodeException
*/
void write(char[] data) throws GuacdException;
/**
* 写入指令
*
* @param opcode opcode
* @param args args
* @throws GuacdException GuacdCodeException
*/
void writeInstruction(String opcode, String... args) throws GuacdException;
/**
* 写入指令
*
* @param opcode opcode
* @param args args
* @throws GuacdException GuacdCodeException
*/
void writeInstruction(String opcode, List<String> args) throws GuacdException;
/**
* 获取 connectionId
*
* @return connectionId
*/
String getConnectionId();
/**
* 获取服务端配置
*
* @return config
*/
GuacamoleConfiguration getServerConfig();
/**
* 获取客户端配置
*
* @return config
*/
GuacamoleClientInformation getClientConfig();
/**
* 是否开启会话
*
* @return open
*/
boolean isOpen();
}

View File

@@ -0,0 +1,402 @@
/*
* 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.guacd.constant;
import java.util.Arrays;
import java.util.List;
/**
* guacd tunnel 常量
* <p>
* <a href="https://guacamole.apache.org/doc/gug/configuring-guacamole.html#vnc">docs</a>
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/31 13:04
*/
public interface GuacdConst {
// -------------------- common --------------------
/**
* 主机
*/
String HOSTNAME = "hostname";
/**
* 端口
*/
String PORT = "port";
/**
* 用户名
*/
String USERNAME = "username";
/**
* 密码
*/
String PASSWORD = "password";
/**
* 颜色深度 8/16/24
*/
String COLOR_DEPTH = "color-depth";
/**
* 无损压缩 boolean
*/
String FORCE_LOSSLESS = "force-lossless";
/**
* 禁用复制 boolean
*/
String DISABLE_COPY = "disable-copy";
/**
* 禁用粘贴 boolean
*/
String DISABLE_PASTE = "disable-paste";
/**
* 屏幕录制文件的目录
*/
String RECORDING_PATH = "recording-path";
/**
* 是否自动创建录屏目录 boolean
*/
String CREATE_RECORDING_PATH = "create-recording-path";
// -------------------- rdp --------------------
/**
* 域
*/
String DOMAIN = "domain";
/**
* 安全模式 默认: any any/nla/nla-ext/tls/vmconnect/rdp
*/
String SECURITY = "security";
/**
* 是否忽略证书 boolean
*/
String IGNORE_CERT = "ignore-cert";
/**
* 是否禁用身份验证 boolean
*/
String DISABLE_AUTH = "disable-auth";
/**
* 剪切板尾行规范化 默认: preserve preserve/unix/windows
*/
String NORMALIZE_CLIPBOARD = "normalize-clipboard";
/**
* 客户端名称 默认为 hostname
*/
String CLIENT_NAME = "client-name";
/**
* 宽度 像素点
*/
String WIDTH = "width";
/**
* 高度 像素点
*/
String HEIGHT = "height";
/**
* 分辨率 dpi
*/
String DPI = "dpi";
/**
* 时区
*/
String TIMEZONE = "timezone";
/**
* 是否连接到控制台会话 boolean
*/
String CONSOLE = "console";
/**
* 立即运行的程序完整路径
*/
String INITIAL_PROGRAM = "initial-program";
/**
* 键盘布局
*/
String SERVER_LAYOUT = "server-layout";
/**
* 重置大小时机 display-update/reconnect
*/
String RESIZE_METHOD = "resize-method";
/**
* 禁用声音输出 boolean
*/
String DISABLE_AUDIO_OUTPUT = "disable-audio";
/**
* 启用麦克风 boolean
*/
String ENABLE_AUDIO_INPUT = "enable-audio-input";
/**
* 启用多点触控 boolean
*/
String ENABLE_TOUCH = "enable-touch";
/**
* 启用打印机 boolean
*/
String ENABLE_PRINTING = "enable-printing";
/**
* 打印机名称 依赖 enable-printing
*/
String PRINTER_NAME = "printer-name";
/**
* 启用文件传输驱动 boolean
*/
String ENABLE_DRIVE = "enable-drive";
/**
* 禁用下载 boolean 依赖 enable-drive
*/
String DISABLE_DOWNLOAD = "disable-download";
/**
* 禁用上传 boolean 依赖 enable-drive
*/
String DISABLE_UPLOAD = "disable-upload";
/**
* 文件系统驱动名称 依赖 enable-drive
*/
String DRIVE_NAME = "drive-name";
/**
* 驱动路径 string 依赖 enable-drive
*/
String DRIVE_PATH = "drive-path";
/**
* 自动创建驱动 boolean 依赖 enable-drive
*/
String CREATE_DRIVE_PATH = "create-drive-path";
/**
* 启动控制台音频 boolean 依赖 console
*/
String CONSOLE_AUDIO = "console-audio";
/**
* 静态管道名称 最大7个字符 多个用,分割
*/
String STATIC_CHANNELS = "static-channels";
/**
* 预连接 id 依赖 security 为 security
*/
String PRE_CONNECTION_ID = "preconnection-id";
/**
* 预连接信息 依赖 security 为 security
*/
String PRE_CONNECTION_BLOB = "preconnection-blob";
/**
* 网关主机名
*/
String GATEWAY_HOSTNAME = "gateway-hostname";
/**
* 网关端口 默认 443
*/
String GATEWAY_PORT = "gateway-port";
/**
* 网关用户名
*/
String GATEWAY_USERNAME = "gateway-username";
/**
* 网关密码
*/
String GATEWAY_PASSWORD = "gateway-password";
/**
* 网关域
*/
String GATEWAY_DOMAIN = "gateway-domain";
/**
* 负载均衡信息
*/
String LOAD_BALANCE_INFO = "load-balance-info";
/**
* 启用壁纸 boolean
*/
String ENABLE_WALLPAPER = "enable-wallpaper";
/**
* 启用主题 boolean
*/
String ENABLE_THEMING = "enable-theming";
/**
* 启动平滑字体 boolean
*/
String ENABLE_FONT_SMOOTHING = "enable-font-smoothing";
/**
* 启用窗口拖动 boolean
*/
String ENABLE_FULL_WINDOW_DRAG = "enable-full-window-drag";
/**
* 启用桌面合成 boolean
*/
String ENABLE_DESKTOP_COMPOSITION = "enable-desktop-composition";
/**
* 启用菜单动画 boolean
*/
String ENABLE_MENU_ANIMATIONS = "enable-menu-animations";
/**
* 禁用位图缓存 boolean
*/
String DISABLE_BITMAP_CACHING = "disable-bitmap-caching";
/**
* 禁用离屏缓存 boolean
*/
String DISABLE_OFFSCREEN_CACHING = "disable-offscreen-caching";
/**
* 禁用字形缓存 boolean 默认禁用
*/
String DISABLE_GLYPH_CACHING = "disable-glyph-caching";
/**
* 远程应用名称
*/
String REMOTE_APP = "remote-app";
/**
* 远程应用程序的工作目录
*/
String REMOTE_APP_DIR = "remote-app-dir";
/**
* 远程应用程序的命令行参数
*/
String REMOTE_APP_ARGS = "remote-app-args";
// -------------------- vnc --------------------
/**
* 重试次数
*/
String AUTO_RETRY = "autoretry";
/**
* 红蓝交换 boolean
*/
String SWAP_RED_BLUE = "swap-red-blue";
/**
* 鼠标指针 remote/local
*/
String CURSOR = "cursor";
/**
* 编码方式
*/
String ENCODINGS = "encodings";
/**
* 是否只读 boolean
*/
String READ_ONLY = "read-only";
/**
* 代理主机
*/
String DEST_HOST = "dest-host";
/**
* 代理端口
*/
String DEST_PORT = "dest-port";
/**
* 反向连接 boolean
*/
String REVERSE_CONNECT = "reverse-connect";
/**
* 监听超时时间 ms
*/
String LISTEN_TIMEOUT = "listen-timeout";
/**
* 是否开启音频 boolean
*/
String ENABLE_AUDIO = "enable-audio";
/**
* 音频服务器 通常为 hostname
*/
String AUDIO_SERVERNAME = "audio-servername";
/**
* 剪贴板编码
*/
String CLIPBOARD_ENCODING = "clipboard-encoding";
// -------------------- const --------------------
String RESIZE_METHOD_DISPLAY_UPDATE = "display-update";
String RESIZE_METHOD_RECONNECT = "reconnect";
String DRIVE_DRIVE_NAME = "Drive";
String SECURITY_VMCONNECT = "vmconnect";
List<String> AUDIO_MIMETYPES = Arrays.asList("audio/L8", "audio/L16");
}

View File

@@ -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.handler.guacd.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* guacd 协议
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/31 15:58
*/
@Getter
@AllArgsConstructor
public enum GuacdProtocol {
/**
* VNC
*/
VNC("vnc"),
/**
* RDP
*/
RDP("rdp"),
;
private final String value;
public static GuacdProtocol of(String protocol) {
if (protocol == null) {
return null;
}
for (GuacdProtocol value : values()) {
if (value.value.equals(protocol) || value.name().equals(protocol)) {
return value;
}
}
return null;
}
}

View File

@@ -0,0 +1,145 @@
/*
* 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;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.FieldConst;
import org.dromara.visor.framework.websocket.core.utils.WebSockets;
import org.dromara.visor.module.terminal.handler.terminal.manager.TerminalManager;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.sender.ITerminalSender;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import javax.annotation.Resource;
import java.util.Map;
/**
* 终端处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/28 14:33
*/
@Slf4j
@Component
public abstract class AbstractTerminalAccessHandler<T extends ITerminalSender> extends AbstractWebSocketHandler {
@Resource
protected TerminalManager terminalManager;
@Override
public void afterConnectionEstablished(WebSocketSession channel) {
String id = channel.getId();
log.info("AbstractTerminalAccessHandler-afterConnectionEstablished id: {}", id);
Map<String, Object> attr = channel.getAttributes();
// 设置消息发送器
T sender = this.createSender(channel);
attr.put(FieldConst.SENDER, sender);
// 设置 sessionId
TerminalChannelProps props = WebSockets.getAttr(channel, FieldConst.PROPS);
props.setId(id);
// 发送 sessionId
sender.sendSetId(id);
// 初始化会话
this.initSession(channel, props);
}
/**
* 创建 sender
*
* @param channel sender
* @return sender
*/
protected abstract T createSender(WebSocketSession channel);
/**
* 初始化会话
*
* @param channel channel
* @param props props
*/
protected void initSession(WebSocketSession channel, TerminalChannelProps props) {
}
/**
* 处理消息
*
* @param channel channel
* @param message message
* @param props props
* @param sender sender
*/
protected abstract void handleMessage(WebSocketSession channel,
TextMessage message,
TerminalChannelProps props,
T sender);
@Override
protected void handleTextMessage(WebSocketSession channel, TextMessage message) {
// 包装处理消息
this.handleMessage(channel, message, this.getProps(channel), this.getSender(channel));
}
@Override
public void handleTransportError(WebSocketSession channel, Throwable exception) {
log.error("AbstractTerminalAccessHandler-handleTransportError id: {}", channel.getId(), exception);
}
@Override
public void afterConnectionClosed(WebSocketSession channel, CloseStatus status) {
String id = channel.getId();
log.info("AbstractTerminalAccessHandler-afterConnectionClosed id: {}, code: {}, reason: {}", id, status.getCode(), status.getReason());
// 设置 sender 为已关闭
T sender = this.getSender(channel);
if (sender != null) {
sender.setClosed();
}
// 关闭会话
terminalManager.closeSession(id);
}
/**
* 获取 sender
*
* @param channel channel
* @return sender
*/
protected T getSender(WebSocketSession channel) {
return WebSockets.getAttr(channel, FieldConst.SENDER);
}
/**
* 获取 props
*
* @param channel channel
* @return props
*/
protected TerminalChannelProps getProps(WebSocketSession channel) {
return WebSockets.getAttr(channel, FieldConst.PROPS);
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.module.terminal.handler.terminal.enums.InputProtocolEnum;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.sender.IGuacdTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.sender.WebsocketGuacdTerminalSender;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* RDP 终端处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/28 14:33
*/
@Slf4j
@Component
public class TerminalAccessRdpHandler extends AbstractTerminalAccessHandler<IGuacdTerminalSender> {
@Override
protected IGuacdTerminalSender createSender(WebSocketSession channel) {
return new WebsocketGuacdTerminalSender(channel);
}
@Override
protected void handleMessage(WebSocketSession channel, TextMessage message, TerminalChannelProps props, IGuacdTerminalSender sender) {
String payload = message.getPayload();
try {
// 解析类型
InputProtocolEnum type = InputProtocolEnum.of(payload);
if (type == null) {
return;
}
// 解析并处理消息
type.getHandler().handle(props, sender, type.parse(payload));
} catch (Exception e) {
log.error("TerminalAccessRdpHandler-handleMessage-error id: {}, msg: {}", channel.getId(), payload, e);
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.module.common.config.AppSftpConfig;
import org.dromara.visor.module.terminal.handler.terminal.enums.InputProtocolEnum;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.sender.WebsocketSftpTerminalSender;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
/**
* sftp 终端处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/28 14:33
*/
@Slf4j
@Component
public class TerminalAccessSftpHandler extends AbstractTerminalAccessHandler<ISftpTerminalSender> {
@Resource
private AppSftpConfig appSftpConfig;
@Override
protected ISftpTerminalSender createSender(WebSocketSession channel) {
return new WebsocketSftpTerminalSender(channel);
}
@Override
protected void initSession(WebSocketSession channel, TerminalChannelProps props) {
// 预览大小
props.getExtra().setFilePreviewSize(appSftpConfig.getPreviewSize());
}
@Override
protected void handleMessage(WebSocketSession channel, TextMessage message, TerminalChannelProps props, ISftpTerminalSender sender) {
String payload = message.getPayload();
try {
// 解析类型
InputProtocolEnum type = InputProtocolEnum.of(payload);
if (type == null) {
return;
}
// 解析并处理消息
type.getHandler().handle(props, sender, type.parse(payload));
} catch (Exception e) {
log.error("TerminalAccessSftpHandler-handleMessage-error id: {}, msg: {}", channel.getId(), payload, e);
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.module.terminal.handler.terminal.enums.InputProtocolEnum;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISshTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.sender.WebsocketSshTerminalSender;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* ssh 终端处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/28 14:33
*/
@Slf4j
@Component
public class TerminalAccessSshHandler extends AbstractTerminalAccessHandler<ISshTerminalSender> {
@Override
protected ISshTerminalSender createSender(WebSocketSession channel) {
return new WebsocketSshTerminalSender(channel);
}
@Override
protected void handleMessage(WebSocketSession channel, TextMessage message, TerminalChannelProps props, ISshTerminalSender sender) {
String payload = message.getPayload();
try {
// 解析类型
InputProtocolEnum type = InputProtocolEnum.of(payload);
if (type == null) {
return;
}
// 解析并处理消息
type.getHandler().handle(props, sender, type.parse(payload));
} catch (Exception e) {
log.error("TerminalAccessSshHandler-handleMessage-error id: {}, msg: {}", channel.getId(), payload, e);
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.constant;
/**
* 会话关闭码
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/4/1 13:53
*/
public interface SessionCloseCode {
/**
* 正常关闭
*/
Integer NORMAL = 0;
/**
* 强制关闭
*/
Integer FORCE_OFFLINE = 10000;
}

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.constant;
package org.dromara.visor.module.terminal.handler.terminal.constant;
/**
* 终端信息常量
@@ -31,18 +31,14 @@ package org.dromara.visor.module.asset.handler.host.terminal.constant;
*/
public interface TerminalMessage {
String CONFIG_DISABLED = "SSH configuration has been disabled.";
String AUTHENTICATION_FAILURE = "authentication failed. please check the configuration.";
String SERVER_UNREACHABLE = "remote server unreachable. please check the configuration.";
String CONFIG_DISABLED = "configuration has been disabled.";
String CONNECTION_FAILED = "connection failed.";
String CONNECTION_TIMEOUT = "connection timeout.";
String CONNECTION_CLOSED = "connection closed.";
String GUACD_SERVICE = "check your guacd service.";
String FORCED_OFFLINE = "forced offline.";
}

View File

@@ -20,53 +20,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.enums;
package org.dromara.visor.module.terminal.handler.terminal.enums;
import cn.orionsec.kit.spring.SpringHolder;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import org.dromara.visor.module.asset.handler.host.terminal.handler.*;
import org.dromara.visor.module.asset.handler.host.terminal.model.TerminalBasePayload;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.*;
import org.dromara.visor.module.terminal.handler.terminal.handler.*;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalBasePayload;
import org.dromara.visor.module.terminal.handler.terminal.model.request.*;
import org.dromara.visor.module.terminal.handler.terminal.sender.ITerminalSender;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 输入操作类型枚举
* 输入协议枚举
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:33
*/
public enum InputTypeEnum {
public enum InputProtocolEnum {
/**
* 终端连接检查
*/
CHECK("ck",
TerminalCheckHandler.class,
new String[]{"type", "sessionId", "hostId", "connectType"},
TerminalCheckRequest.class,
true),
/**
* 连接主机
* 连接终端
*/
CONNECT("co",
TerminalConnectHandler.class,
new String[]{"type", "sessionId", "terminalType", "cols", "rows"},
TerminalConnectRequest.class,
true),
new String[]{"type", "body"},
TerminalConnectRequest.class),
/**
* 关闭连接
*/
CLOSE("cl",
TerminalCloseHandler.class,
new String[]{"type", "sessionId"},
TerminalBasePayload.class,
true),
new String[]{"type"},
TerminalBasePayload.class),
/**
* ping
@@ -74,116 +64,133 @@ public enum InputTypeEnum {
PING("p",
TerminalPingHandler.class,
new String[]{"type"},
TerminalBasePayload.class,
true),
TerminalBasePayload.class),
/**
* SSH 修改大小
* 修改大小
*/
SSH_RESIZE("rs",
SshResizeHandler.class,
new String[]{"type", "sessionId", "cols", "rows"},
SshResizeRequest.class,
true),
RESIZE("rs",
TerminalResizeHandler.class,
new String[]{"type", "width", "height"},
TerminalResizeRequest.class),
// ----------------------- SSH ----------------------
/**
* SSH 输入
*/
SSH_INPUT("i",
SshInputHandler.class,
new String[]{"type", "sessionId", "command"},
SshInputRequest.class,
false),
new String[]{"type", "command"},
SshInputRequest.class),
// ----------------------- SFTP ----------------------
/**
* SFTP 文件列表
*/
SFTP_LIST("ls",
SftpListHandler.class,
new String[]{"type", "sessionId", "showHiddenFile", "path"},
SftpListRequest.class,
true),
new String[]{"type", "showHiddenFile", "path"},
SftpListRequest.class),
/**
* SFTP 创建文件夹
*/
SFTP_MKDIR("mk",
SftpMakeDirectoryHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
/**
* SFTP 创建文件
*/
SFTP_TOUCH("to",
SftpTouchHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
/**
* SFTP 移动文件
*/
SFTP_MOVE("mv",
SftpMoveHandler.class,
new String[]{"type", "sessionId", "path", "target"},
SftpMoveRequest.class,
true),
new String[]{"type", "path", "target"},
SftpMoveRequest.class),
/**
* SFTP 删除文件
*/
SFTP_REMOVE("rm",
SftpRemoveHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
/**
* SFTP 截断文件
*/
SFTP_TRUNCATE("tc",
SftpTruncateHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
/**
* SFTP 修改文件权限
*/
SFTP_CHMOD("cm",
SFTP_CHMOD("chm",
SftpChangeModeHandler.class,
new String[]{"type", "sessionId", "path", "mod"},
SftpChangeModeRequest.class,
true),
new String[]{"type", "path", "mod"},
SftpChangeModeRequest.class),
/**
* SFTP 修改文件归属
*/
SFTP_CHOWN("cho",
SftpChangeOwnerHandler.class,
new String[]{"type", "path", "uid"},
SftpChangeOwnerRequest.class),
/**
* SFTP 修改文件分组
*/
SFTP_CHGRP("chg",
SftpChangeGroupHandler.class,
new String[]{"type", "path", "gid"},
SftpChangeGroupRequest.class),
/**
* SFTP 下载文件夹展开文件
*/
SFTP_DOWNLOAD_FLAT_DIRECTORY("df",
SftpDownloadFlatDirectoryHandler.class,
new String[]{"type", "sessionId", "currentPath", "path"},
SftpDownloadFlatDirectoryRequest.class,
true),
new String[]{"type", "currentPath", "path"},
SftpDownloadFlatDirectoryRequest.class),
/**
* SFTP 获取内容
*/
SFTP_GET_CONTENT("gc",
SftpGetContentHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
/**
* SFTP 修改内容
*/
SFTP_SET_CONTENT("sc",
SftpSetContentHandler.class,
new String[]{"type", "sessionId", "path"},
SftpBaseRequest.class,
true),
new String[]{"type", "path"},
SftpBaseRequest.class),
// ----------------------- guacd ----------------------
/**
* guacd 指令
*/
GUACD_INSTRUCTION("gi",
GuacdInstructionHandler.class,
new String[]{"type", "instruction"},
GuacdInstructionRequest.class),
;
@@ -192,35 +199,29 @@ public enum InputTypeEnum {
@Getter
private final String type;
private final Class<? extends ITerminalHandler<? extends TerminalBasePayload>> handlerBean;
private final Class<? extends ITerminalHandler<? extends ITerminalSender, ? extends TerminalBasePayload>> handlerBean;
private final String[] payloadDefine;
private final Class<? extends TerminalBasePayload> payloadClass;
@Getter
private final boolean asyncExec;
private ITerminalHandler<? extends ITerminalSender, ? extends TerminalBasePayload> handler;
@Getter
private ITerminalHandler<? extends TerminalBasePayload> handler;
<T extends TerminalBasePayload> InputTypeEnum(String type,
Class<? extends ITerminalHandler<T>> handlerBean,
String[] payloadDefine,
Class<T> payloadClass,
boolean asyncExec) {
<S extends ITerminalSender, T extends TerminalBasePayload> InputProtocolEnum(String type,
Class<? extends ITerminalHandler<S, T>> handlerBean,
String[] payloadDefine,
Class<T> payloadClass) {
this.type = type;
this.handlerBean = handlerBean;
this.payloadDefine = payloadDefine;
this.payloadClass = payloadClass;
this.asyncExec = asyncExec;
}
public static InputTypeEnum of(String payload) {
public static InputProtocolEnum of(String payload) {
if (payload == null) {
return null;
}
for (InputTypeEnum value : values()) {
for (InputProtocolEnum value : values()) {
if (payload.startsWith(value.type + SEPARATOR) || payload.equals(value.type)) {
return value;
}
@@ -262,6 +263,11 @@ public enum InputTypeEnum {
return (T) object.toJavaObject(payloadClass);
}
@SuppressWarnings("unchecked")
public <S extends ITerminalSender, T extends TerminalBasePayload> ITerminalHandler<S, T> getHandler() {
return (ITerminalHandler<S, T>) handler;
}
/**
* 类型字段定义
*/
@@ -270,7 +276,7 @@ public enum InputTypeEnum {
@PostConstruct
public void init() {
for (InputTypeEnum value : InputTypeEnum.values()) {
for (InputProtocolEnum value : InputProtocolEnum.values()) {
value.handler = SpringHolder.getBean(value.handlerBean);
}
}

View File

@@ -20,14 +20,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.enums;
package org.dromara.visor.module.terminal.handler.terminal.enums;
import cn.orionsec.kit.lang.utils.json.matcher.ReplacementFormatters;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 输出操作类型枚举
* 输出协议枚举
*
* @author Jiahang Li
* @version 1.0.0
@@ -35,82 +35,120 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum OutputTypeEnum {
public enum OutputProtocolEnum {
// ----------------------- base ----------------------
/**
* 终端连接检查
* 设置id
*/
CHECK("ck", "${type}|${sessionId}|${result}|${msg}"),
SET_ID("id", "${type}|${sessionId}"),
/**
* 终端连接
* 设置会话信息
*/
CONNECT("co", "${type}|${sessionId}|${result}|${msg}"),
SET_INFO("if", "${type}|${info}"),
/**
* 关闭连接
* 连接
*/
CLOSE("cl", "${type}|${sessionId}|${forceClose}|${msg}"),
CONNECTED("co", "${type}"),
/**
* 已关闭
*/
CLOSED("cl", "${type}|${code}|${msg}"),
/**
* pong
*/
PONG("p", "${type}"),
/**
* 修改大小
*/
RESIZE("rs", "${type}|${width}|${height}"),
// ----------------------- ssh ----------------------
/**
* SSH 输出
*/
SSH_OUTPUT("o", "${type}|${sessionId}|${body}"),
SSH_OUTPUT("o", "${type}|${body}"),
/**
* SSH sz 下载文件
*/
SSH_SZ_DOWNLOAD("szd", "${type}|${paths}"),
// ----------------------- sftp ----------------------
/**
* SFTP 文件列表
*/
SFTP_LIST("ls", "${type}|${sessionId}|${path}|${result}|${msg}|${body}"),
SFTP_LIST("ls", "${type}|${path}|${result}|${msg}|${body}"),
/**
* SFTP 创建文件夹
*/
SFTP_MKDIR("mk", "${type}|${sessionId}|${result}|${msg}"),
SFTP_MKDIR("mk", "${type}|${result}|${msg}"),
/**
* SFTP 创建文件
*/
SFTP_TOUCH("to", "${type}|${sessionId}|${result}|${msg}"),
SFTP_TOUCH("to", "${type}|${result}|${msg}"),
/**
* SFTP 移动文件
*/
SFTP_MOVE("mv", "${type}|${sessionId}|${result}|${msg}"),
SFTP_MOVE("mv", "${type}|${result}|${msg}"),
/**
* SFTP 删除文件
*/
SFTP_REMOVE("rm", "${type}|${sessionId}|${result}|${msg}"),
SFTP_REMOVE("rm", "${type}|${result}|${msg}"),
/**
* SFTP 截断文件
*/
SFTP_TRUNCATE("tc", "${type}|${sessionId}|${result}|${msg}"),
SFTP_TRUNCATE("tc", "${type}|${result}|${msg}"),
/**
* SFTP 修改文件权限
*/
SFTP_CHMOD("cm", "${type}|${sessionId}|${result}|${msg}"),
SFTP_CHMOD("chm", "${type}|${result}|${msg}"),
/**
* SFTP 修改文件归属
*/
SFTP_CHOWN("cho", "${type}|${result}|${msg}"),
/**
* SFTP 修改文件分组
*/
SFTP_CHGRP("chg", "${type}|${result}|${msg}"),
/**
* SFTP 下载文件夹展开文件
*/
SFTP_DOWNLOAD_FLAT_DIRECTORY("df", "${type}|${sessionId}|${currentPath}|${result}|${msg}|${body}"),
SFTP_DOWNLOAD_FLAT_DIRECTORY("df", "${type}|${currentPath}|${result}|${msg}|${body}"),
/**
* SFTP 获取文件内容
*/
SFTP_GET_CONTENT("gc", "${type}|${sessionId}|${result}|${msg}|${token}"),
SFTP_GET_CONTENT("gc", "${type}|${result}|${msg}|${token}"),
/**
* SFTP 修改文件内容
*/
SFTP_SET_CONTENT("sc", "${type}|${sessionId}|${result}|${msg}|${token}"),
SFTP_SET_CONTENT("sc", "${type}|${result}|${msg}|${token}"),
// ----------------------- guacd ----------------------
/**
* guacd 指令
*/
GUACD_INSTRUCTION("gi", "${type}|${instruction}"),
;
@@ -128,11 +166,11 @@ public enum OutputTypeEnum {
return ReplacementFormatters.format(this.template, o);
}
public static OutputTypeEnum of(String type) {
public static OutputProtocolEnum of(String type) {
if (type == null) {
return null;
}
for (OutputTypeEnum value : values()) {
for (OutputProtocolEnum value : values()) {
if (value.type.equals(type)) {
return value;
}

View File

@@ -20,15 +20,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.infra.constant;
package org.dromara.visor.module.terminal.handler.terminal.enums;
/**
* 数据额外字段常量
* session channel
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/19 22:26
* @since 2024/8/19 15:04
*/
public interface DataExtraItems {
public enum SessionChannelEnum {
/**
* web
*/
WEB,
}

View File

@@ -20,14 +20,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.common.validator.group;
package org.dromara.visor.module.terminal.handler.terminal.enums;
/**
* 导出验证分组
* session 类型
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/1 19:13
* @since 2024/7/5 10:51
*/
public interface Export {
public enum SessionTypeEnum {
/**
* 终端
*/
TERMINAL,
/**
* 传输
*/
TRANSFER,
}

View File

@@ -0,0 +1,121 @@
/*
* 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 org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.framework.biz.operator.log.core.model.OperatorLogModel;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.terminal.handler.terminal.constant.SessionCloseCode;
import org.dromara.visor.module.terminal.handler.terminal.manager.TerminalManager;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalBasePayload;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.model.config.ITerminalSessionConfig;
import org.dromara.visor.module.terminal.handler.terminal.record.TerminalAsyncSaver;
import org.dromara.visor.module.terminal.handler.terminal.sender.ITerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ITerminalSession;
import org.dromara.visor.module.terminal.handler.terminal.utils.TerminalUtils;
import javax.annotation.Resource;
import java.util.Map;
/**
* 终端消息处理器 基类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 18:59
*/
public abstract class AbstractTerminalHandler<S extends ITerminalSender, T extends TerminalBasePayload>
implements ITerminalHandler<S, T> {
@Resource
protected TerminalManager terminalManager;
/**
* 保存操作日志
*
* @param props props
* @param extra extra
* @param type type
* @param startTime startTime
* @param ex ex
* @return model
*/
protected OperatorLogModel saveOperatorLog(TerminalChannelProps props,
Map<String, Object> extra,
String type,
long startTime,
Exception ex) {
String sessionId = props.getId();
// 获取会话并且设置参数
ITerminalSession session = terminalManager.getSession(sessionId);
if (session != null) {
ITerminalSessionConfig config = session.getConfig();
extra.put(OperatorLogs.HOST_ID, config.getHostId());
extra.put(OperatorLogs.HOST_NAME, config.getHostName());
extra.put(OperatorLogs.ADDRESS, config.getHostAddress());
}
extra.put(OperatorLogs.SESSION_ID, sessionId);
// 获取日志
OperatorLogModel model = TerminalUtils.getOperatorLogModel(props, extra, type, startTime, ex);
// 保存操作日志
TerminalAsyncSaver.saveOperatorLog(model);
return model;
}
/**
* 获取错误信息
*
* @param ex ex
* @return msg
*/
protected String getErrorMessage(Exception ex) {
// 获取错误信息
return ErrorMessage.getErrorMessage(ex, ErrorMessage.OPERATE_ERROR);
}
/**
* 发送 closed 消息以及关闭
*
* @param sender sender
* @param message message
*/
protected void sendClosedAndClose(S sender, String message) {
this.sendClosedAndClose(sender, SessionCloseCode.NORMAL, message);
}
/**
* 发送 closed 消息以及关闭
*
* @param sender sender
* @param code code
* @param message message
*/
protected void sendClosedAndClose(S sender, int code, String message) {
// 发送消息
sender.sendClosed(code, message);
// 关闭 sender
sender.close();
}
}

View File

@@ -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.handler.terminal.handler;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.model.request.GuacdInstructionRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.IGuacdTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.IRdpSession;
import org.dromara.visor.module.terminal.handler.terminal.session.ITerminalSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* guacd 指令处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/2/19 11:13
*/
@Slf4j
@Component
public class GuacdInstructionHandler extends AbstractTerminalHandler<IGuacdTerminalSender, GuacdInstructionRequest> {
@Override
public void handle(TerminalChannelProps props, IGuacdTerminalSender sender, GuacdInstructionRequest payload) {
// 获取会话
ITerminalSession session = terminalManager.getSession(props.getId());
if (session instanceof IRdpSession) {
// 处理 rdp 指令
this.processRdpInstruction((IRdpSession) session, payload.getInstruction());
}
}
/**
* 处理 rdp 指令
*
* @param session session
* @param instruction instruction
*/
private void processRdpInstruction(IRdpSession session, String instruction) {
session.write(instruction);
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 org.dromara.visor.module.terminal.handler.terminal.model.TerminalBasePayload;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.sender.ITerminalSender;
/**
* 终端消息处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 18:53
*/
public interface ITerminalHandler<S extends ITerminalSender, T extends TerminalBasePayload> {
/**
* 处理消息
*
* @param props props
* @param sender sender
* @param payload payload
*/
void handle(TerminalChannelProps props, S sender, T payload);
}

View File

@@ -0,0 +1,77 @@
/*
* 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 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.SftpChangeGroupRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* sftp 修改分组权限 处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/2/19 11:13
*/
@Slf4j
@Component
public class SftpChangeGroupHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpChangeGroupRequest> {
@Override
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpChangeGroupRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
Integer gid = payload.getGid();
log.info("SftpChangeGroupHandler-handle start sessionId: {}, path: {}, gid: {}", sessionId, path, gid);
Exception ex = null;
// 修改权限
try {
session.changeGroup(path, gid);
log.info("SftpChangeGroupHandler-handle success sessionId: {}, path: {}, gid: {}", sessionId, path, gid);
} catch (Exception e) {
log.error("SftpChangeGroupHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回结果
sender.sendChangeGroupResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
extra.put(OperatorLogs.ID, gid);
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_CHGRP,
startTime, ex);
}
}

View File

@@ -20,24 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpChangeModeRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpBaseResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.SftpChangeModeRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* sftp 修改文件权限
* sftp 修改文件权限 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -45,39 +43,33 @@ import java.util.Map;
*/
@Slf4j
@Component
public class SftpChangeModeHandler extends AbstractTerminalHandler<SftpChangeModeRequest> {
public class SftpChangeModeHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpChangeModeRequest> {
@Override
public void handle(WebSocketSession channel, SftpChangeModeRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpChangeModeRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
Integer mod = payload.getMod();
log.info("SftpChangeModeHandler-handle start sessionId: {}, path: {}, mod: {}", sessionId, path, mod);
Exception ex = null;
// 修改权限
try {
session.chmod(path, mod);
session.changeMode(path, mod);
log.info("SftpChangeModeHandler-handle success sessionId: {}, path: {}, mod: {}", sessionId, path, mod);
} catch (Exception e) {
log.error("SftpChangeModeHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_CHMOD,
SftpBaseResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendChangeModeResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
extra.put(OperatorLogs.MOD, mod);
this.saveOperatorLog(payload, channel,
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_CHMOD,
startTime, ex);
}

View File

@@ -0,0 +1,77 @@
/*
* 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 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.SftpChangeOwnerRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* sftp 修改文件归属 处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/2/19 11:13
*/
@Slf4j
@Component
public class SftpChangeOwnerHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpChangeOwnerRequest> {
@Override
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpChangeOwnerRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
Integer uid = payload.getUid();
log.info("SftpChangeOwnerHandler-handle start sessionId: {}, path: {}, uid: {}", sessionId, path, uid);
Exception ex = null;
// 修改归属
try {
session.changeOwner(path, uid);
log.info("SftpChangeOwnerHandler-handle success sessionId: {}, path: {}, uid: {}", sessionId, path, uid);
} catch (Exception e) {
log.error("SftpChangeOwnerHandler-handle error sessionId: {},", sessionId, e);
ex = e;
}
// 返回结果
sender.sendChangeOwnerResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
extra.put(OperatorLogs.ID, uid);
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_CHOWN,
startTime, ex);
}
}

View File

@@ -20,25 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpDownloadFlatDirectoryRequest;
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.session.ISftpSession;
import cn.orionsec.kit.lang.utils.collect.Lists;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpDownloadFlatDirectoryRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpDownloadFlatDirectoryResponse;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpFileVO;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Arrays;
import java.util.List;
/**
* sftp 下载文件夹展开文件
* sftp 下载文件夹展开文件 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -46,13 +43,13 @@ import java.util.List;
*/
@Slf4j
@Component
public class SftpDownloadFlatDirectoryHandler extends AbstractTerminalHandler<SftpDownloadFlatDirectoryRequest> {
public class SftpDownloadFlatDirectoryHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpDownloadFlatDirectoryRequest> {
@Override
public void handle(WebSocketSession channel, SftpDownloadFlatDirectoryRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpDownloadFlatDirectoryRequest payload) {
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(props.getId());
String[] paths = payload.getPath().split("\\|");
log.info("SftpDownloadFlatDirectoryHandler-handle start sessionId: {}, paths: {}", sessionId, Arrays.toString(paths));
Exception ex = null;
@@ -65,16 +62,8 @@ public class SftpDownloadFlatDirectoryHandler extends AbstractTerminalHandler<Sf
log.error("SftpDownloadFlatDirectoryHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_DOWNLOAD_FLAT_DIRECTORY,
SftpDownloadFlatDirectoryResponse.builder()
.sessionId(sessionId)
.currentPath(payload.getCurrentPath())
.body(JSON.toJSONString(files))
.result(BooleanBit.of(ex == null).getValue())
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendDownloadFlatDirectory(payload.getCurrentPath(), ex == null, this.getErrorMessage(ex), files);
}
}

View File

@@ -20,23 +20,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.id.UUIds;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
import org.dromara.visor.module.asset.define.cache.TerminalCacheKeyDefine;
import org.dromara.visor.module.asset.entity.dto.SftpGetContentCacheDTO;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpBaseRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpGetContentResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.handler.terminal.model.TerminalChannelProps;
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.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* sftp 获取文件内容
* sftp 获取文件内容 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -44,20 +47,21 @@ import org.springframework.web.socket.WebSocketSession;
*/
@Slf4j
@Component
public class SftpGetContentHandler extends AbstractTerminalHandler<SftpBaseRequest> {
public class SftpGetContentHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpBaseRequest> {
@Override
public void handle(WebSocketSession channel, SftpBaseRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
log.info("SftpGetContentHandler-handle start sessionId: {}, path: {}", sessionId, path);
String token = UUIds.random32();
Exception ex = null;
try {
// 检查文件是否可编辑
session.checkCanEdit(path);
// 检查文件编辑权限
session.checkEditPermission(path);
// 设置缓存
String key = TerminalCacheKeyDefine.TERMINAL_SFTP_GET_CONTENT.format(token);
SftpGetContentCacheDTO cache = SftpGetContentCacheDTO.builder()
@@ -70,15 +74,14 @@ public class SftpGetContentHandler extends AbstractTerminalHandler<SftpBaseReque
log.error("SftpGetContentHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_GET_CONTENT,
SftpGetContentResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.token(token)
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendGetContentResult(ex == null, this.getErrorMessage(ex), token);
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_GET_CONTENT,
startTime, ex);
}
}

View File

@@ -20,24 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.utils.collect.Lists;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpListRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpFileVO;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpListResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
import org.dromara.visor.module.terminal.handler.terminal.model.TerminalChannelProps;
import org.dromara.visor.module.terminal.handler.terminal.model.request.SftpListRequest;
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.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.List;
/**
* sftp 文件列表
* sftp 文件列表 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -45,15 +43,15 @@ import java.util.List;
*/
@Slf4j
@Component
public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
public class SftpListHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpListRequest> {
private static final String HOME_PATH = "~";
@Override
public void handle(WebSocketSession channel, SftpListRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpListRequest payload) {
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
log.info("SftpListHandler-handle start sessionId: {}, path: {}", sessionId, path);
Exception ex = null;
@@ -70,15 +68,8 @@ public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
log.error("SftpListHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_LIST,
SftpListResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.path(path)
.body(JSON.toJSONString(list))
.build());
// 返回结果
sender.sendFileList(path, ex == null, this.getErrorMessage(ex), list);
}
}

View File

@@ -20,24 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpBaseRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpBaseResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.SftpBaseRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* sftp 创建文件夹
* sftp 创建文件夹 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -45,14 +43,14 @@ import java.util.Map;
*/
@Slf4j
@Component
public class SftpMakeDirectoryHandler extends AbstractTerminalHandler<SftpBaseRequest> {
public class SftpMakeDirectoryHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpBaseRequest> {
@Override
public void handle(WebSocketSession channel, SftpBaseRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
log.info("SftpMakeDirectoryHandler-handle start sessionId: {}, path: {}", sessionId, path);
Exception ex = null;
@@ -64,18 +62,12 @@ public class SftpMakeDirectoryHandler extends AbstractTerminalHandler<SftpBaseRe
log.error("SftpMakeDirectoryHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_MKDIR,
SftpBaseResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendMakeDirectoryResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
this.saveOperatorLog(payload, channel,
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_MKDIR,
startTime, ex);
}

View File

@@ -20,24 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpMoveRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpBaseResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.SftpMoveRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* sftp 移动文件
* sftp 移动文件 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -45,14 +43,14 @@ import java.util.Map;
*/
@Slf4j
@Component
public class SftpMoveHandler extends AbstractTerminalHandler<SftpMoveRequest> {
public class SftpMoveHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpMoveRequest> {
@Override
public void handle(WebSocketSession channel, SftpMoveRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpMoveRequest payload) {
long startTime = System.currentTimeMillis();
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
String sessionId = props.getId();
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
String target = payload.getTarget();
log.info("SftpMoveHandler-handle start sessionId: {}, path: {}, target: {}", sessionId, path, target);
@@ -65,19 +63,13 @@ public class SftpMoveHandler extends AbstractTerminalHandler<SftpMoveRequest> {
log.error("SftpMoveHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_MOVE,
SftpBaseResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendMoveResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
extra.put(OperatorLogs.TARGET, target);
this.saveOperatorLog(payload, channel,
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_MOVE,
startTime, ex);
}

View File

@@ -20,25 +20,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpBaseRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpBaseResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.SftpBaseRequest;
import org.dromara.visor.module.terminal.handler.terminal.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Arrays;
import java.util.Map;
/**
* sftp 删除文件
* sftp 删除文件 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -46,15 +44,15 @@ import java.util.Map;
*/
@Slf4j
@Component
public class SftpRemoveHandler extends AbstractTerminalHandler<SftpBaseRequest> {
public class SftpRemoveHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpBaseRequest> {
@Override
public void handle(WebSocketSession channel, SftpBaseRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
long startTime = System.currentTimeMillis();
String path = payload.getPath();
String sessionId = payload.getSessionId();
String sessionId = props.getId();
// 获取会话
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
ISftpSession session = terminalManager.getSession(sessionId);
String[] paths = path.split("\\|");
log.info("SftpRemoveHandler-handle start sessionId: {}, path: {}", sessionId, Arrays.toString(paths));
Exception ex = null;
@@ -66,18 +64,12 @@ public class SftpRemoveHandler extends AbstractTerminalHandler<SftpBaseRequest>
log.error("SftpRemoveHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_REMOVE,
SftpBaseResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendRemoveResult(ex == null, this.getErrorMessage(ex));
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
this.saveOperatorLog(payload, channel,
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_REMOVE,
startTime, ex);
}

View File

@@ -20,28 +20,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.terminal.handler;
package org.dromara.visor.module.terminal.handler.terminal.handler;
import cn.orionsec.kit.lang.id.UUIds;
import cn.orionsec.kit.lang.utils.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.enums.BooleanBit;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
import org.dromara.visor.module.asset.define.cache.TerminalCacheKeyDefine;
import org.dromara.visor.module.asset.define.operator.TerminalOperatorType;
import org.dromara.visor.module.asset.entity.dto.SftpSetContentCacheDTO;
import org.dromara.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import org.dromara.visor.module.asset.handler.host.terminal.model.request.SftpBaseRequest;
import org.dromara.visor.module.asset.handler.host.terminal.model.response.SftpSetContentResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ISftpSession;
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.SftpSetContentCacheDTO;
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.sender.ISftpTerminalSender;
import org.dromara.visor.module.terminal.handler.terminal.session.ISftpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* sftp 设置文件内容
* sftp 设置文件内容 处理器
*
* @author Jiahang Li
* @version 1.0.0
@@ -49,21 +47,21 @@ import java.util.Map;
*/
@Slf4j
@Component
public class SftpSetContentHandler extends AbstractTerminalHandler<SftpBaseRequest> {
public class SftpSetContentHandler extends AbstractTerminalHandler<ISftpTerminalSender, SftpBaseRequest> {
@Override
public void handle(WebSocketSession channel, SftpBaseRequest payload) {
public void handle(TerminalChannelProps props, ISftpTerminalSender sender, SftpBaseRequest payload) {
long startTime = System.currentTimeMillis();
String sessionId = props.getId();
// 获取会话
String sessionId = payload.getSessionId();
ISftpSession session = terminalManager.getSession(channel.getId(), sessionId);
ISftpSession session = terminalManager.getSession(sessionId);
String path = payload.getPath();
log.info("SftpSetContentHandler-handle start sessionId: {}, path: {}", sessionId, path);
String token = UUIds.random32();
Exception ex = null;
try {
// 检查文件是否可编辑
session.checkCanEdit(path);
// 检查文件编辑权限
session.checkEditPermission(path);
// 设置缓存
String key = TerminalCacheKeyDefine.TERMINAL_SFTP_SET_CONTENT.format(token);
SftpSetContentCacheDTO cache = SftpSetContentCacheDTO.builder()
@@ -76,19 +74,12 @@ public class SftpSetContentHandler extends AbstractTerminalHandler<SftpBaseReque
log.error("SftpSetContentHandler-handle error sessionId: {}", sessionId, e);
ex = e;
}
// 返回
this.send(channel,
OutputTypeEnum.SFTP_SET_CONTENT,
SftpSetContentResponse.builder()
.sessionId(sessionId)
.result(BooleanBit.of(ex == null).getValue())
.token(token)
.msg(this.getErrorMessage(ex))
.build());
// 返回结果
sender.sendSetContentResult(ex == null, this.getErrorMessage(ex), token);
// 保存操作日志
Map<String, Object> extra = Maps.newMap();
extra.put(OperatorLogs.PATH, path);
this.saveOperatorLog(payload, channel,
this.saveOperatorLog(props,
extra, TerminalOperatorType.SFTP_SET_CONTENT,
startTime, ex);
}

Some files were not shown because too many files have changed in this diff Show More