Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80e7c28ef1 | ||
|
|
154f8d56ac | ||
|
|
156e63bef9 | ||
|
|
34d65c0bc5 | ||
|
|
decbce5410 | ||
|
|
8b795e889a | ||
|
|
b75446f405 | ||
|
|
2b43270896 | ||
|
|
9d4c2aaeb4 | ||
|
|
712b175179 | ||
|
|
10178d998e | ||
|
|
c603c57ad8 | ||
|
|
f69093de66 | ||
|
|
cec7e21d5a | ||
|
|
f1ade56e13 | ||
|
|
b182452f30 | ||
|
|
5ed513f472 | ||
|
|
aa8b380289 | ||
|
|
6149010bf4 | ||
|
|
5183b7ccb4 | ||
|
|
f78958532b | ||
|
|
603dd89be4 | ||
|
|
1a58e40607 | ||
|
|
84721f2e17 | ||
|
|
d72ccb1df6 | ||
|
|
6d4952c483 | ||
|
|
7fab68f8c0 | ||
|
|
3a586c47a3 | ||
|
|
1767079249 | ||
|
|
fdd3be5a91 | ||
|
|
2457a015e4 | ||
|
|
40a99eb67a | ||
|
|
1fcf239561 | ||
|
|
bbb1bb0db6 | ||
|
|
f79d89def9 | ||
|
|
fd535f00c8 | ||
|
|
2c07551b88 | ||
|
|
86914321a6 | ||
|
|
f64c15a01b | ||
|
|
8265cc3cfd | ||
|
|
84c8bc98af | ||
|
|
858ca1becc | ||
|
|
0e0c9cc628 | ||
|
|
cdc3c88507 | ||
|
|
10624b42c4 | ||
|
|
6479694b4b | ||
|
|
d2e72aea56 | ||
|
|
986f0974db | ||
|
|
6b5c7fd409 | ||
|
|
ca803e4e5a | ||
|
|
5de22e4b41 | ||
|
|
b8e81ee100 | ||
|
|
0b53924dbd | ||
|
|
3359d163fb | ||
|
|
2ef1517338 | ||
|
|
a5bee66afa | ||
|
|
88fd0e31e0 | ||
|
|
226dfb2c25 | ||
|
|
94ed071897 | ||
|
|
4efd2b5ec2 | ||
|
|
76e766367f | ||
|
|
b3009bb65e | ||
|
|
819520ef73 | ||
|
|
a2acbc0c3a | ||
|
|
2e8a7c40d9 | ||
|
|
94c0b6a785 | ||
|
|
9752dfa680 | ||
|
|
bc776e4186 | ||
|
|
cdce5a0dc1 | ||
|
|
0db732fc19 | ||
|
|
69f331c048 | ||
|
|
032f1763f6 | ||
|
|
d071ef64d8 | ||
|
|
c820443a3b | ||
|
|
14c4e77445 | ||
|
|
79d9f69ed4 | ||
|
|
6c9065072d | ||
|
|
05bc6c1fbb | ||
|
|
a1dd9eec01 | ||
|
|
660df7c110 | ||
|
|
093501a400 | ||
|
|
7943deb924 | ||
|
|
490167e649 | ||
|
|
8635f6bb05 | ||
|
|
9e31d820e0 | ||
|
|
92353d859a | ||
|
|
bef8d69e59 | ||
|
|
ac46dd6703 | ||
|
|
b3ab78e063 | ||
|
|
95d2c6cb65 | ||
|
|
7017c7502b | ||
|
|
c14055ba8c | ||
|
|
04aa6c9680 | ||
|
|
397bbb2657 | ||
|
|
9a68282127 | ||
|
|
dcd02acc61 |
12
.env.example
12
.env.example
@@ -1,6 +1,11 @@
|
||||
SERVICE_PORT=1081
|
||||
VOLUME_BASE=/data/orion-visor-space/docker-volumes
|
||||
|
||||
DEMO_MODE=false
|
||||
|
||||
SERVICE_PORT=1081
|
||||
SPRING_PROFILES_ACTIVE=prod
|
||||
SECRET_KEY=uQeacXV8b3isvKLK
|
||||
|
||||
MYSQL_HOST=mysql
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_DATABASE=orion_visor
|
||||
@@ -11,5 +16,6 @@ MYSQL_ROOT_PASSWORD=Data@123456
|
||||
REDIS_HOST=redis
|
||||
REDIS_PASSWORD=Data@123456
|
||||
|
||||
SECRET_KEY=uQeacXV8b3isvKLK
|
||||
DEMO_MODE=false
|
||||
GUACD_HOST=guacd
|
||||
GUACD_PORT=4822
|
||||
GUACD_DRIVE_PATH=/drive
|
||||
|
||||
51
README.md
51
README.md
@@ -1,4 +1,4 @@
|
||||
<div align="center"><img src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/9/11/11e7e78e-2af0-4c68-9811-db8a4c4400f4.png" alt="logo" width="520" /></div>
|
||||
<div align="center"><img src="https://oss.orionsec.cn/orion-visor/logo_horizontal.png" alt="logo" width="520" /></div>
|
||||
<p style="margin-top: 12px" align="center"><b>【Dromara】 一款高颜值、现代化的自动化运维&轻量堡垒机平台。</b></p>
|
||||
<p align="center">
|
||||
<a target="_blank"
|
||||
@@ -48,7 +48,7 @@
|
||||
**`orion-visor`** 提供一站式自动化运维解决方案。
|
||||
|
||||
* **资产管理**:支持对资产进行分组,实现对主机、密钥和身份的统一管理和授权。
|
||||
* **在线终端**:提供在线终端 SSH 服务,支持快捷命令、自定义快捷键和主题风格。
|
||||
* **在线终端**:提供在线终端 SSH/RDP 等多种协议,支持快捷命令、自定义快捷键和主题风格。
|
||||
* **文件管理**:支持远程主机 SFTP 大文件的批量上传、下载和在线编辑等操作。
|
||||
* **批量操作**:支持批量执行主机命令、多主机文件分发等功能。
|
||||
* **计划任务**:支持配置 cron 表达式,定时执行主机命令。
|
||||
@@ -64,6 +64,7 @@
|
||||
* 🎭 演示环境部分功能不可用, 完整功能请本地部署!
|
||||
* 📛 演示环境请不要随便删除数据!
|
||||
* 📧 如果演示环境不可用请联系我!
|
||||
* 📨 **作者已被毕(cai)业(yuan) 寻java高级内推 望京/5号/10号线 有坑位的联系我哦(随缘)** 微信: `ljh1553488`
|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -86,32 +87,42 @@ docker compose up -d
|
||||
|
||||
## 技术栈
|
||||
|
||||
* SpringBoot 2.7+
|
||||
* Mysql 8+
|
||||
* Redis 6+
|
||||
* Vue3 3+
|
||||
* Arco Design 2+
|
||||
* SpringBoot 2.7.17
|
||||
* Mysql 8.0+
|
||||
* Redis 6.0+
|
||||
* Vue3 3.5+
|
||||
* Arco Design 2.56+
|
||||
|
||||
## 主要功能预览
|
||||
|
||||
#### 工作台
|
||||
|
||||

|
||||
|
||||
#### 主机终端
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
#### 主机列表
|
||||
|
||||

|
||||
|
||||
#### 批量执行
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
#### 批量上传
|
||||
|
||||

|
||||

|
||||
|
||||
#### 计划任务
|
||||
|
||||

|
||||

|
||||
|
||||
## Star History
|
||||
|
||||
@@ -123,7 +134,7 @@ docker compose up -d
|
||||
|
||||
## 联系我
|
||||
|
||||
<img src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/10/11/cf72c603-3951-4171-95b4-06271dda1c80.jpg" alt="wx" width="628px"/>
|
||||
<img src="https://oss.orionsec.cn/orion-visor/vx.jpg" alt="vx" width="628px"/>
|
||||
|
||||
微信: ljh1553488
|
||||
QQ群: 755242157
|
||||
@@ -133,7 +144,7 @@ QQ群: 755242157
|
||||
|
||||
## 支持一下
|
||||
|
||||
<img src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/5/17/a5351e59-294c-4bec-b767-1a44c362fcbc.jpg" alt="收款码" width="540px"/>
|
||||
<img src="https://oss.orionsec.cn/orion-visor/pay.jpg" alt="收款码" width="540px"/>
|
||||
|
||||
🎁 为了项目能健康持续的发展, 我期望获得相应的资金支持, 你们的支持是我不断更新前进的动力!
|
||||
|
||||
@@ -145,6 +156,10 @@ QQ群: 755242157
|
||||
|
||||
本项目遵循 [Apache-2.0](https://github.com/dromara/orion-visor/blob/main/LICENSE) 开源许可证。
|
||||
|
||||
## Gitee 最有价值开源项目 GVP
|
||||
## Gitee 最有价值的开源项目 GVP
|
||||
|
||||

|
||||

|
||||
|
||||
## GitCode 最有影响力的开源项目 G-Star
|
||||
|
||||

|
||||
|
||||
@@ -1,79 +1,90 @@
|
||||
version: '3.3'
|
||||
|
||||
services:
|
||||
service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- 1081:80
|
||||
- 9200:9200
|
||||
environment:
|
||||
- MYSQL_HOST=mysql
|
||||
- MYSQL_PORT=3306
|
||||
- MYSQL_DATABASE=orion_visor
|
||||
- MYSQL_USER=root
|
||||
- MYSQL_PASSWORD=Data@123456
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PASSWORD=Data@123456
|
||||
- SECRET_KEY=uQeacXV8b3isvKLK
|
||||
- DEMO_MODE=false
|
||||
SPRING_PROFILES_ACTIVE: prod
|
||||
MYSQL_HOST: mysql
|
||||
MYSQL_PORT: 3306
|
||||
MYSQL_DATABASE: orion_visor
|
||||
MYSQL_USER: root
|
||||
MYSQL_PASSWORD: Data@123456
|
||||
REDIS_HOST: redis
|
||||
REDIS_PASSWORD: Data@123456
|
||||
SECRET_KEY: uQeacXV8b3isvKLK
|
||||
DEMO_MODE: false
|
||||
volumes:
|
||||
- /data/orion-visor-space/docker-volumes/service/root-orion:/root/orion
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health" ]
|
||||
interval: 3s
|
||||
timeout: 300s
|
||||
retries: 200
|
||||
start_period: 3s
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 15s
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- mysql
|
||||
- redis
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
environment:
|
||||
- MYSQL_DATABASE=orion_visor
|
||||
- MYSQL_USER=orion
|
||||
- MYSQL_PASSWORD=Data@123456
|
||||
- MYSQL_ROOT_PASSWORD=Data@123456
|
||||
MYSQL_DATABASE: orion_visor
|
||||
MYSQL_USER: orion
|
||||
MYSQL_PASSWORD: Data@123456
|
||||
MYSQL_ROOT_PASSWORD: Data@123456
|
||||
volumes:
|
||||
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql:/var/lib/mysql
|
||||
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql-files:/var/lib/mysql-files
|
||||
- /data/orion-visor-space/docker-volumes/mysql/etc-mysql:/etc/mysql
|
||||
healthcheck:
|
||||
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
|
||||
interval: 3s
|
||||
timeout: 60s
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 3s
|
||||
start_period: 5s
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
environment:
|
||||
- REDIS_PASSWORD=Data@123456
|
||||
REDIS_PASSWORD: Data@123456
|
||||
volumes:
|
||||
- /data/orion-visor-space/docker-volumes/redis/data:/data
|
||||
command: sh -c "redis-server /usr/local/redis.conf --requirepass $${REDIS_PASSWORD}"
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
|
||||
interval: 3s
|
||||
timeout: 60s
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 3s
|
||||
start_period: 5s
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
testing:
|
||||
build:
|
||||
context: ./docker/e2e
|
||||
environment:
|
||||
SERVER: http://service:80
|
||||
SERVER: http://service:9200
|
||||
depends_on:
|
||||
service:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- service
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
networks:
|
||||
orion-visor-net:
|
||||
driver: bridge
|
||||
@@ -1,78 +1,131 @@
|
||||
version: '3.3'
|
||||
|
||||
# latest = 2.4.0
|
||||
services:
|
||||
ui:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:latest
|
||||
ports:
|
||||
- ${SERVICE_PORT:-1081}:80
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
service:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- ${SERVICE_PORT:-1081}:80
|
||||
- 9200:9200
|
||||
environment:
|
||||
- MYSQL_HOST=${MYSQL_HOST:-mysql}
|
||||
- MYSQL_PORT=${MYSQL_PORT:-3306}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE:-orion_visor}
|
||||
- MYSQL_USER=${MYSQL_USER:-root}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD:-Data@123456}
|
||||
- REDIS_HOST=${REDIS_HOST:-redis}
|
||||
- REDIS_PASSWORD=${REDIS_PASSWORD:-Data@123456}
|
||||
- SECRET_KEY=${SECRET_KEY:-uQeacXV8b3isvKLK}
|
||||
- DEMO_MODE=${DEMO_MODE:-false}
|
||||
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
|
||||
MYSQL_HOST: ${MYSQL_HOST:-mysql}
|
||||
MYSQL_PORT: ${MYSQL_PORT:-3306}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-orion_visor}
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Data@123456}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD:-Data@123456}
|
||||
GUACD_HOST: ${GUACD_HOST:-guacd}
|
||||
GUACD_PORT: ${GUACD_PORT:-4822}
|
||||
GUACD_DRIVE_PATH: ${GUACD_DRIVE_PATH:-/drive}
|
||||
SECRET_KEY: ${SECRET_KEY:-uQeacXV8b3isvKLK}
|
||||
DEMO_MODE: ${DEMO_MODE:-false}
|
||||
volumes:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/service/root-orion:/root/orion
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health" ]
|
||||
interval: 15s
|
||||
timeout: 300s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
start_period: 30s
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- mysql
|
||||
- redis
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
environment:
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE:-orion_visor}
|
||||
- MYSQL_USER=${MYSQL_USER:-orion}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD:-Data@123456}
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-Data@123456}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-orion_visor}
|
||||
MYSQL_USER: ${MYSQL_USER:-orion}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Data@123456}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Data@123456}
|
||||
volumes:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/mysql/var-lib-mysql:/var/lib/mysql
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/mysql/var-lib-mysql-files:/var/lib/mysql-files
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/mysql/etc-mysql:/etc/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
|
||||
interval: 15s
|
||||
timeout: 60s
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
environment:
|
||||
- REDIS_PASSWORD=${REDIS_PASSWORD:-Data@123456}
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD:-Data@123456}
|
||||
volumes:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/redis/data:/data
|
||||
command: sh -c "redis-server /usr/local/redis.conf --requirepass $${REDIS_PASSWORD}"
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
|
||||
interval: 15s
|
||||
timeout: 60s
|
||||
retries: 15
|
||||
start_period: 3s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
guacd:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:latest
|
||||
ports:
|
||||
- 4822:4822
|
||||
environment:
|
||||
GUACD_LOG_LEVEL: info
|
||||
GUACD_LOG_FILE: /var/log/guacd.log
|
||||
volumes:
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/guacd/drive:${GUACD_DRIVE_PATH:-/drive}
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/guacd/var-logs:/var/log
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/guacd/local-guacamole-lib:/usr/local/guacamole/lib
|
||||
- ${VOLUME_BASE:-/data/orion-visor-space/docker-volumes}/guacd/local-guacamole-extensions:/usr/local/guacamole/extensions
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "nc", "-vz", "localhost", "4822" ]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
adminer:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest
|
||||
ports:
|
||||
- 8081:8080
|
||||
environment:
|
||||
ADMINER_DEFAULT_SERVER: ${MYSQL_HOST:-mysql}
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- mysql
|
||||
networks:
|
||||
- orion-visor-net
|
||||
|
||||
networks:
|
||||
orion-visor-net:
|
||||
driver: bridge
|
||||
@@ -1,7 +1,16 @@
|
||||
#/bin/bash
|
||||
docker compose down
|
||||
# demo 启动
|
||||
#!/bin/bash
|
||||
|
||||
# 停止并移除现有容器
|
||||
docker compose down --remove-orphans
|
||||
|
||||
if [ "$1" == "demo" ]; then
|
||||
sed -i 's/\${DEMO_MODE:-false}/true/g' docker-compose.yml
|
||||
# 设置 DEMO_MODE 环境变量为 true
|
||||
export DEMO_MODE=true
|
||||
echo "Starting services for demo mode..."
|
||||
# 启动指定的服务
|
||||
docker compose up -d --remove-orphans mysql redis ui service adminer
|
||||
else
|
||||
echo "Starting all services..."
|
||||
# 正常启动所有服务
|
||||
docker compose up -d --remove-orphans
|
||||
fi
|
||||
docker compose up -d --remove-orphans
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#/bin/bash
|
||||
version=2.3.2
|
||||
set -e
|
||||
version=2.4.0
|
||||
docker build -t orion-visor-adminer:${version} .
|
||||
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
||||
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
|
||||
name: orion-visor
|
||||
api: |
|
||||
{{default "http://orion-visor-service:80" (env "SERVER")}}
|
||||
{{default "http://service:9200" (env "SERVER")}}
|
||||
items:
|
||||
- name: login
|
||||
request:
|
||||
|
||||
10
docker/guacd/Dockerfile
Normal file
10
docker/guacd/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM guacamole/guacd:1.5.5
|
||||
USER root
|
||||
# 系统时区
|
||||
ARG TZ=Asia/Shanghai
|
||||
# 设置时区
|
||||
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \
|
||||
echo '${TZ}' > /etc/timezone
|
||||
|
||||
# 创建所需目录
|
||||
RUN mkdir -p /home/guacd/drive /usr/share/guacd/drive
|
||||
6
docker/guacd/build.sh
Normal file
6
docker/guacd/build.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#/bin/bash
|
||||
set -e
|
||||
version=2.4.0
|
||||
docker build -t orion-visor-guacd:${version} .
|
||||
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:${version}
|
||||
docker tag orion-visor-guacd:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:latest
|
||||
@@ -1,5 +1,6 @@
|
||||
#/bin/bash
|
||||
version=2.3.2
|
||||
set -e
|
||||
version=2.4.0
|
||||
cp -r ../../sql ./sql
|
||||
docker build -t orion-visor-mysql:${version} .
|
||||
rm -rf ./sql
|
||||
|
||||
@@ -12,7 +12,7 @@ socket=/var/run/mysqld/mysqld.sock
|
||||
# 数据目录
|
||||
datadir=/var/lib/mysql
|
||||
# 不区分大小 0区分 1不区分
|
||||
lower_case_table_names=1
|
||||
lower_case_table_names=0
|
||||
# 服务器时区
|
||||
default-time_zone='+8:00'
|
||||
# 服务端字符集
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#/bin/bash
|
||||
version=2.3.2
|
||||
set -e
|
||||
version=2.4.0
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-guacd:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:latest
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:latest
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#/bin/bash
|
||||
version=2.3.2
|
||||
set -e
|
||||
version=2.4.0
|
||||
docker build -t orion-visor-redis:${version} .
|
||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
|
||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM nginx:alpine
|
||||
FROM openjdk:8-jdk-alpine
|
||||
USER root
|
||||
WORKDIR /app
|
||||
# 系统时区
|
||||
@@ -7,18 +7,14 @@ ARG TZ=Asia/Shanghai
|
||||
RUN \
|
||||
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk add curl && \
|
||||
apk add udev && \
|
||||
apk add tzdata && \
|
||||
apk add dmidecode && \
|
||||
apk add openjdk8
|
||||
apk add dmidecode
|
||||
# 设置时区
|
||||
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \
|
||||
echo '${TZ}' > /etc/timezone
|
||||
# 删除原 nginx 配置
|
||||
RUN rm -rf /etc/nginx/conf.d/*
|
||||
# 复制包
|
||||
COPY ./orion-visor-launch.jar /app/app.jar
|
||||
COPY ./dist /usr/share/nginx/html
|
||||
COPY ./entrypoint.sh /app/entrypoint.sh
|
||||
COPY ./nginx.conf /etc/nginx/conf.d
|
||||
# 启动
|
||||
ENTRYPOINT [ "sh", "/app/entrypoint.sh" ]
|
||||
CMD ["java", "-jar", "/app/app.jar"]
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#/bin/bash
|
||||
version=2.3.2
|
||||
set -e
|
||||
version=2.4.0
|
||||
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
|
||||
mv ../../orion-visor-ui/dist ./dist
|
||||
docker build --no-cache -t orion-visor-service:${version} .
|
||||
docker build -t orion-visor-service:${version} .
|
||||
rm -rf ./orion-visor-launch.jar
|
||||
rm -rf ./dist
|
||||
docker tag orion-visor-service:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:${version}
|
||||
docker tag orion-visor-service:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-service:latest
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
cd /app
|
||||
nohup java -jar app.jar --spring.profiles.active=prod 2>&1 &
|
||||
nginx -g 'daemon off;'
|
||||
18
docker/ui/Dockerfile
Normal file
18
docker/ui/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM nginx:alpine
|
||||
# 系统时区
|
||||
ARG TZ=Asia/Shanghai
|
||||
# 添加包
|
||||
RUN \
|
||||
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk add tzdata
|
||||
# 设置时区
|
||||
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \
|
||||
echo '${TZ}' > /etc/timezone
|
||||
# 删除原 nginx 配置
|
||||
RUN rm -rf /etc/nginx/conf.d/*
|
||||
# 复制包
|
||||
COPY ./dist /usr/share/nginx/html
|
||||
COPY ./nginx.conf /etc/nginx/conf.d
|
||||
# 启动
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
9
docker/ui/build.sh
Normal file
9
docker/ui/build.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#/bin/bash
|
||||
set -e
|
||||
version=2.4.0
|
||||
mv ../../orion-visor-ui/dist ./dist
|
||||
docker build -t orion-visor-ui:${version} .
|
||||
rm -rf ./orion-visor-launch.jar
|
||||
rm -rf ./dist
|
||||
docker tag orion-visor-ui:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:${version}
|
||||
docker tag orion-visor-ui:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-ui:latest
|
||||
@@ -19,7 +19,7 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# web history 模式 404
|
||||
@@ -27,7 +27,7 @@ server {
|
||||
}
|
||||
|
||||
location /orion-visor/api {
|
||||
proxy_pass http://localhost:9200/orion-visor/api;
|
||||
proxy_pass http://service:9200/orion-visor/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@@ -35,7 +35,7 @@ server {
|
||||
}
|
||||
|
||||
location /orion-visor/keep-alive {
|
||||
proxy_pass http://localhost:9200/orion-visor/keep-alive;
|
||||
proxy_pass http://service:9200/orion-visor/keep-alive;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
@@ -20,21 +20,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.launch.configuration;
|
||||
package org.dromara.visor.common.configuration;
|
||||
|
||||
import cn.orionsec.kit.spring.SpringHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 应用配置类
|
||||
* spring 配置类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/20 10:34
|
||||
*/
|
||||
@Configuration
|
||||
public class LaunchApplicationConfiguration {
|
||||
public class SpringConfiguration {
|
||||
|
||||
/**
|
||||
* @return spring 容器工具类
|
||||
@@ -36,7 +36,7 @@ public interface AppConst extends OrionConst {
|
||||
/**
|
||||
* 同 ${orion.version} 迭代时候需要手动更改
|
||||
*/
|
||||
String VERSION = "2.3.2";
|
||||
String VERSION = "2.4.0";
|
||||
|
||||
/**
|
||||
* 同 ${spring.application.name}
|
||||
|
||||
@@ -51,6 +51,11 @@ public interface Const extends cn.orionsec.kit.lang.constant.Const, FieldConst,
|
||||
|
||||
String SYSTEM_USERNAME = "system";
|
||||
|
||||
// FIXME KIT
|
||||
String ADMINISTRATOR = "Administrator";
|
||||
|
||||
Long ALL_HOST_ID = -1L;
|
||||
|
||||
int BATCH_COUNT = 500;
|
||||
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public enum ErrorCode implements CodeInfo {
|
||||
|
||||
EXCEL_PASSWORD_ERROR(905, "文档密码错误"),
|
||||
|
||||
PASER_FAILED(906, "解析失败"),
|
||||
PASER_FAILED(906, "表达式解析失败"),
|
||||
|
||||
ENCRYPT_ERROR(907, "数据加密异常"),
|
||||
|
||||
@@ -134,9 +134,10 @@ public enum ErrorCode implements CodeInfo {
|
||||
* 获取 wapper
|
||||
*
|
||||
* @param data data
|
||||
* @param <T> T
|
||||
* @return HttpWrapper
|
||||
*/
|
||||
public HttpWrapper<?> wrapper() {
|
||||
public <T> HttpWrapper<T> wrapper() {
|
||||
return HttpWrapper.of(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,14 @@ package org.dromara.visor.common.constant;
|
||||
|
||||
import cn.orionsec.kit.lang.exception.ApplicationException;
|
||||
import cn.orionsec.kit.lang.exception.argument.InvalidArgumentException;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
@@ -52,6 +60,12 @@ public interface ErrorMessage {
|
||||
|
||||
String IDENTITY_ABSENT = "主机身份不存在";
|
||||
|
||||
String CHECK_IDENTITY_PASSWORD = "请选择类型为[密码]的主机身份";
|
||||
|
||||
String KEY_ABSENT_WITH = "主机密钥不存在 {}";
|
||||
|
||||
String IDENTITY_ABSENT_WITH = "主机身份不存在 {}";
|
||||
|
||||
String CONFIG_ABSENT = "配置不存在";
|
||||
|
||||
String CONFIG_PRESENT = "配置已存在";
|
||||
@@ -90,28 +104,42 @@ public interface ErrorMessage {
|
||||
|
||||
String HOST_NOT_ENABLED = "主机未启用";
|
||||
|
||||
String CONFIG_NOT_ENABLED = "配置未启用";
|
||||
|
||||
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
|
||||
|
||||
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";
|
||||
|
||||
String DECRYPT_ERROR = "数据解密失败";
|
||||
|
||||
String PASSWORD_MISSING = "请输入密码";
|
||||
|
||||
String BEFORE_PASSWORD_ERROR = "原密码错误";
|
||||
|
||||
String DATA_NO_PERMISSION = "数据无权限";
|
||||
|
||||
String EXPRESSION_ERROR = "表达式错误";
|
||||
|
||||
String ANY_NO_PERMISSION = "{}无权限";
|
||||
|
||||
String OPT_NO_PERMISSION = "无操作权限";
|
||||
|
||||
String SESSION_PRESENT = "会话已存在";
|
||||
|
||||
String SESSION_ABSENT = "会话不存在";
|
||||
|
||||
String SESSION_CLOSED = "会话已关闭";
|
||||
|
||||
String USER_UNSUPPORTED_OPT = "用户不支持此操作";
|
||||
|
||||
String CURRENT_USER_UNSUPPORTED_OPT = "当前" + USER_UNSUPPORTED_OPT;
|
||||
|
||||
String PATH_NOT_NORMALIZE = "路径不合法";
|
||||
|
||||
String OPERATE_ERROR = "操作失败";
|
||||
|
||||
String ENCRYPT_KEY_UNSET = "加密密钥未配置";
|
||||
|
||||
String DECRYPT_ERROR = "数据解密失败";
|
||||
|
||||
String UNKNOWN_TYPE = "未知类型";
|
||||
|
||||
String ERROR_TYPE = "错误的类型";
|
||||
@@ -146,8 +174,26 @@ public interface ErrorMessage {
|
||||
|
||||
String CLIENT_ABORT = "手动中断";
|
||||
|
||||
String COMMAND_EXEC_ERROR = "命令执行失败 [{}]";
|
||||
|
||||
String COMPRESS_ERROR = "压缩失败";
|
||||
|
||||
String DECOMPRESS_ERROR = "解压失败";
|
||||
|
||||
String COMPRESS_FILE_ABSENT = "压缩文件不存在";
|
||||
|
||||
String UNABLE_DOWNLOAD_FOLDER = "无法下载文件夹";
|
||||
|
||||
String VALID_ERROR = "验证失败";
|
||||
|
||||
String CONVERT_ERROR = "转换失败";
|
||||
|
||||
String PRESENT_MODIFY = "{} 已存在, 请修改后重试";
|
||||
|
||||
String ILLEGAL_MODIFY = "{} 不正确, 请修改后重试";
|
||||
|
||||
String PLEASE_SELECT_SUFFIX_FILE = "请选择 {} 类型的文件";
|
||||
|
||||
/**
|
||||
* 是否为业务异常
|
||||
*
|
||||
@@ -185,4 +231,37 @@ public interface ErrorMessage {
|
||||
return defaultMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证错误消息
|
||||
*
|
||||
* @param ex ex
|
||||
* @param defaultMsg defaultMsg
|
||||
* @return message
|
||||
*/
|
||||
static String getValidErrorMessage(Exception ex, String defaultMsg) {
|
||||
if (ex == null) {
|
||||
return null;
|
||||
}
|
||||
// 参数不存在异常
|
||||
if (ex instanceof MissingServletRequestParameterException) {
|
||||
return Strings.format(ErrorMessage.MISSING, ((MissingServletRequestParameterException) ex).getParameterName());
|
||||
}
|
||||
// 参数绑定异常
|
||||
if (ex instanceof BindException) {
|
||||
return Optional.ofNullable(((BindException) ex)
|
||||
.getFieldError())
|
||||
.map(error -> error.getField() + Const.SPACE + error.getDefaultMessage())
|
||||
.orElse(defaultMsg);
|
||||
}
|
||||
// 参数验证异常
|
||||
if (ex instanceof ConstraintViolationException) {
|
||||
return Optional.ofNullable(((ConstraintViolationException) ex).getConstraintViolations())
|
||||
.map(Set::iterator)
|
||||
.map(Iterator::next)
|
||||
.map(s -> s.getPropertyPath().toString() + Const.SPACE + s.getMessage())
|
||||
.orElse(defaultMsg);
|
||||
}
|
||||
return getErrorMessage(ex, defaultMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public interface ExtraFieldConst extends FieldConst {
|
||||
|
||||
String GRANT_NAME = "grantName";
|
||||
|
||||
String CHANNEL_ID = "channelId";
|
||||
String CHANNEL = "channel";
|
||||
|
||||
String SESSION_ID = "sessionId";
|
||||
|
||||
|
||||
@@ -103,8 +103,20 @@ public interface FieldConst {
|
||||
|
||||
String FILTER = "filter";
|
||||
|
||||
String LICENSE = "license";
|
||||
|
||||
String SESSION = "session";
|
||||
|
||||
String CONNECT = "connect";
|
||||
|
||||
String ALL = "all";
|
||||
|
||||
String PROPS = "props";
|
||||
|
||||
String SENDER = "sender";
|
||||
|
||||
String RESULT = "result";
|
||||
|
||||
String CONFIG = "config";
|
||||
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@ import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 公共页码请求
|
||||
* 基本查询请求
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/12 23:14
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "PageRequest", description = "公共页码请求")
|
||||
public class PageRequest {
|
||||
@Schema(name = "BaseQueryRequest", description = "基本查询请求")
|
||||
public class BaseQueryRequest implements IPageRequest, IOrderRequest {
|
||||
|
||||
@NotNull(groups = Page.class)
|
||||
@Min(value = 1, groups = Page.class)
|
||||
@@ -53,4 +53,7 @@ public class PageRequest {
|
||||
@Schema(description = "大小")
|
||||
private Integer limit;
|
||||
|
||||
@Schema(description = "查询排序")
|
||||
private Integer order;
|
||||
|
||||
}
|
||||
@@ -20,14 +20,22 @@
|
||||
* 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.common.entity;
|
||||
|
||||
/**
|
||||
* 导出验证分组
|
||||
* 查询排序请求
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/9/1 19:13
|
||||
* @since 2025/3/17 22:04
|
||||
*/
|
||||
public interface Import {
|
||||
public interface IOrderRequest {
|
||||
|
||||
/**
|
||||
* 查询排序
|
||||
*
|
||||
* @return sort 0DESC 1ASC 其他不排序
|
||||
*/
|
||||
Integer getOrder();
|
||||
|
||||
}
|
||||
@@ -20,21 +20,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.handler.host.jsch;
|
||||
package org.dromara.visor.common.entity;
|
||||
|
||||
/**
|
||||
* 连接消息
|
||||
* 页码请求
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/7/11 16:30
|
||||
* @since 2025/3/17 22:02
|
||||
*/
|
||||
public interface SessionMessage {
|
||||
public interface IPageRequest {
|
||||
|
||||
String AUTHENTICATION_FAILURE = "authentication failed. please check the configuration. - {}";
|
||||
/**
|
||||
* 页码
|
||||
*
|
||||
* @return page
|
||||
*/
|
||||
Integer getPage();
|
||||
|
||||
String SERVER_UNREACHABLE = "remote server unreachable. please check the configuration. - {}";
|
||||
|
||||
String CONNECTION_TIMEOUT = "connection timeout. - {}";
|
||||
/**
|
||||
* 大小
|
||||
*
|
||||
* @return limit
|
||||
*/
|
||||
Integer getLimit();
|
||||
|
||||
}
|
||||
@@ -52,14 +52,26 @@ public enum EnableStatus {
|
||||
|
||||
public static EnableStatus of(Integer value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
return DISABLED;
|
||||
}
|
||||
for (EnableStatus e : values()) {
|
||||
if (e.value.equals(value)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return DISABLED;
|
||||
}
|
||||
|
||||
public static EnableStatus of(String value) {
|
||||
if (value == null) {
|
||||
return DISABLED;
|
||||
}
|
||||
for (EnableStatus e : values()) {
|
||||
if (e.name().equals(value)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return DISABLED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.enums;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.time.DateStream;
|
||||
import cn.orionsec.kit.lang.utils.time.Dates;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 统计区间枚举
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/23 14:02
|
||||
*/
|
||||
public enum StatisticsRange {
|
||||
|
||||
/**
|
||||
* 当天
|
||||
*/
|
||||
TODAY {
|
||||
@Override
|
||||
public Date getRangeEndTime(Date startTime) {
|
||||
return DateStream.of(startTime)
|
||||
.dayEnd()
|
||||
.date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDateRanges(Date startTime) {
|
||||
return Lists.singleton(Dates.format(startTime, Dates.YMD));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 日视图
|
||||
*/
|
||||
DAY {
|
||||
@Override
|
||||
public Date getRangeEndTime(Date startTime) {
|
||||
return DateStream.of(startTime)
|
||||
.dayEnd()
|
||||
.date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDateRanges(Date startTime) {
|
||||
return Lists.singleton(Dates.format(startTime, Dates.YMD));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 周视图
|
||||
*/
|
||||
WEEK {
|
||||
@Override
|
||||
public Date getRangeEndTime(Date startTime) {
|
||||
return DateStream.of(startTime)
|
||||
.addDay(7)
|
||||
.dayEnd()
|
||||
.date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDateRanges(Date startTime) {
|
||||
return Arrays.stream(Dates.getIncrementDayDates(startTime, 1, 7))
|
||||
.map(s -> Dates.format(s, Dates.YMD))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 月视图
|
||||
*/
|
||||
MONTH {
|
||||
@Override
|
||||
public Date getRangeEndTime(Date startTime) {
|
||||
return DateStream.of(startTime)
|
||||
.addMonth(1)
|
||||
.dayEnd()
|
||||
.date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDateRanges(Date startTime) {
|
||||
int monthLastDay = Dates.getMonthLastDay(startTime);
|
||||
return Arrays.stream(Dates.getIncrementDayDates(startTime, 1, monthLastDay - 1))
|
||||
.map(s -> Dates.format(s, Dates.YMD))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 获取区间结束时间
|
||||
*
|
||||
* @param startTime startTime
|
||||
* @return end
|
||||
*/
|
||||
public abstract Date getRangeEndTime(Date startTime);
|
||||
|
||||
/**
|
||||
* 获取时间区间
|
||||
*
|
||||
* @param startTime startTime
|
||||
* @return ranges
|
||||
*/
|
||||
public abstract List<String> getDateRanges(Date startTime);
|
||||
|
||||
public static StatisticsRange of(String type) {
|
||||
if (type == null) {
|
||||
return TODAY;
|
||||
}
|
||||
for (StatisticsRange value : values()) {
|
||||
if (value.name().equals(type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return TODAY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,7 +44,6 @@ public interface GenericsDataModel {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转为 map
|
||||
*
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.mapstruct;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* json 转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/3/7 17:43
|
||||
*/
|
||||
public class JsonConversion {
|
||||
|
||||
private JsonConversion() {
|
||||
}
|
||||
|
||||
/**
|
||||
* JSONString > JSONObject
|
||||
*
|
||||
* @param json json
|
||||
* @return JSONObject
|
||||
*/
|
||||
public static JSONObject stringToJsonObject(String json) {
|
||||
return json != null ? JSON.parseObject(json) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSONString > JSONArray.
|
||||
*
|
||||
* @param json json
|
||||
* @return JSONArray
|
||||
*/
|
||||
public static JSONArray stringToJsonArray(String json) {
|
||||
return json != null ? JSON.parseArray(json) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSONObject > JSONString.
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @return JSONString
|
||||
*/
|
||||
public static String jsonObjectToString(JSONObject jsonObject) {
|
||||
return jsonObject != null ? jsonObject.toJSONString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSONArray > JSONString.
|
||||
*
|
||||
* @param jsonArray JSONArray
|
||||
* @return JSONString
|
||||
*/
|
||||
public static String jsonArrayToString(JSONArray jsonArray) {
|
||||
return jsonArray != null ? jsonArray.toJSONString() : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.mapstruct;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* string 转换器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/3/7 17:35
|
||||
*/
|
||||
public class StringConversion {
|
||||
|
||||
private StringConversion() {
|
||||
}
|
||||
|
||||
/**
|
||||
* String > List<Integer>
|
||||
*
|
||||
* @param str str
|
||||
* @return list
|
||||
*/
|
||||
public static List<Integer> stringToIntegerList(String str) {
|
||||
if (Strings.isBlank(str)) {
|
||||
return Lists.newList();
|
||||
}
|
||||
return Arrays.stream(str.split(Const.COMMA))
|
||||
.map(Integer::valueOf)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* String > List<String>
|
||||
*
|
||||
* @param str str
|
||||
* @return list
|
||||
*/
|
||||
public static List<Long> stringToLongList(String str) {
|
||||
if (Strings.isBlank(str)) {
|
||||
return Lists.newList();
|
||||
}
|
||||
return Arrays.stream(str.split(Const.COMMA))
|
||||
.map(Long::valueOf)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* String > List<String>
|
||||
*
|
||||
* @param str str
|
||||
* @return list
|
||||
*/
|
||||
public static List<String> stringToStringList(String str) {
|
||||
if (Strings.isBlank(str)) {
|
||||
return Lists.newList();
|
||||
}
|
||||
return Lists.of(str.split(Const.COMMA));
|
||||
}
|
||||
|
||||
/**
|
||||
* List<Integer> String
|
||||
*
|
||||
* @param list list
|
||||
* @return str
|
||||
*/
|
||||
public static String integerListToString(List<Integer> list) {
|
||||
if (list != null) {
|
||||
return list.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(Const.COMMA));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List<Long> String
|
||||
*
|
||||
* @param list list
|
||||
* @return str
|
||||
*/
|
||||
public static String longListToString(List<Long> list) {
|
||||
if (list != null) {
|
||||
return list.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(Const.COMMA));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List<String> String
|
||||
*
|
||||
* @param list list
|
||||
* @return str
|
||||
*/
|
||||
public static String stringListToString(List<String> list) {
|
||||
return list != null ? String.join(Const.COMMA, list) : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,4 +45,11 @@ public interface SecurityHolder {
|
||||
*/
|
||||
Long getLoginUserId();
|
||||
|
||||
/**
|
||||
* 获取当前用户名
|
||||
*
|
||||
* @return username
|
||||
*/
|
||||
String getLoginUsername();
|
||||
|
||||
}
|
||||
|
||||
@@ -47,4 +47,11 @@ public interface UpdatePasswordAction extends Serializable {
|
||||
*/
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* 设置密码
|
||||
*
|
||||
* @param password password
|
||||
*/
|
||||
void setPassword(String password);
|
||||
|
||||
}
|
||||
|
||||
@@ -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.common.session;
|
||||
|
||||
import cn.orionsec.kit.lang.exception.AuthenticationException;
|
||||
import cn.orionsec.kit.lang.exception.argument.InvalidArgumentException;
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
|
||||
/**
|
||||
* 连接消息
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/7/11 16:30
|
||||
*/
|
||||
public interface SessionMessage {
|
||||
|
||||
String AUTHENTICATION_FAILURE = "身份认证失败. {}";
|
||||
|
||||
String SERVER_UNREACHABLE = "无法连接至服务器. {}";
|
||||
|
||||
String CONNECTION_TIMEOUT = "连接服务器超时. {}";
|
||||
|
||||
/**
|
||||
* 获取错误信息
|
||||
*
|
||||
* @param address address
|
||||
* @param e e
|
||||
* @return errorMessage
|
||||
*/
|
||||
static String getErrorMessage(String address, Exception e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
String message = e.getMessage();
|
||||
if (Strings.contains(message, Const.TIMEOUT)) {
|
||||
// 连接超时
|
||||
return Strings.format(SessionMessage.CONNECTION_TIMEOUT, address);
|
||||
} else if (Exceptions.isCausedBy(e, AuthenticationException.class)) {
|
||||
// 认证失败
|
||||
return Strings.format(SessionMessage.AUTHENTICATION_FAILURE, address);
|
||||
} else if (Exceptions.isCausedBy(e, InvalidArgumentException.class)) {
|
||||
// 参数错误
|
||||
if (Strings.isBlank(message)) {
|
||||
return Strings.format(SessionMessage.SERVER_UNREACHABLE, address);
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
} else {
|
||||
// 其他错误
|
||||
return Strings.format(SessionMessage.SERVER_UNREACHABLE, address);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.session.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 基础连接配置实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/4/1 16:59
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "BaseConnectConfig", description = "基础连接参数")
|
||||
public class BaseConnectConfig implements IBaseConnectConfig {
|
||||
|
||||
@Schema(description = "系统类型")
|
||||
private String osType;
|
||||
|
||||
@Schema(description = "系统架构")
|
||||
private String archType;
|
||||
|
||||
@Schema(description = "hostId")
|
||||
private Long hostId;
|
||||
|
||||
@Schema(description = "hostName")
|
||||
private String hostName;
|
||||
|
||||
@Schema(description = "主机编码")
|
||||
private String hostCode;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String hostAddress;
|
||||
|
||||
@Schema(description = "主机端口")
|
||||
private Integer hostPort;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.session.config;
|
||||
|
||||
/**
|
||||
* 基础连接配置定义
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/6/24 17:11
|
||||
*/
|
||||
public interface IBaseConnectConfig {
|
||||
|
||||
// -------------------- getter/setter --------------------
|
||||
|
||||
String getOsType();
|
||||
|
||||
void setOsType(String osType);
|
||||
|
||||
String getArchType();
|
||||
|
||||
void setArchType(String archType);
|
||||
|
||||
Long getHostId();
|
||||
|
||||
void setHostId(Long hostId);
|
||||
|
||||
String getHostName();
|
||||
|
||||
void setHostName(String hostName);
|
||||
|
||||
String getHostCode();
|
||||
|
||||
void setHostCode(String hostCode);
|
||||
|
||||
String getHostAddress();
|
||||
|
||||
void setHostAddress(String hostAddress);
|
||||
|
||||
Integer getHostPort();
|
||||
|
||||
void setHostPort(Integer hostPort);
|
||||
|
||||
String getUsername();
|
||||
|
||||
void setUsername(String username);
|
||||
|
||||
String getPassword();
|
||||
|
||||
void setPassword(String password);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.common.session.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* RDP 连接参数
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/4/1 16:57
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(name = "RdpConnectConfig", description = "RDP 连接参数")
|
||||
public class RdpConnectConfig extends BaseConnectConfig {
|
||||
|
||||
@Schema(description = "低带宽模式")
|
||||
private Boolean lowBandwidthMode;
|
||||
|
||||
@Schema(description = "RDP 版本是否大于8.1")
|
||||
private Boolean versionGt81;
|
||||
|
||||
@Schema(description = "时区")
|
||||
private String timezone;
|
||||
|
||||
@Schema(description = "键盘布局")
|
||||
private String keyboardLayout;
|
||||
|
||||
@Schema(description = "剪切板规范")
|
||||
private String clipboardNormalize;
|
||||
|
||||
@Schema(description = "域")
|
||||
private String domain;
|
||||
|
||||
@Schema(description = "预连接id")
|
||||
private String preConnectionId;
|
||||
|
||||
@Schema(description = "预连接数据")
|
||||
private String preConnectionBlob;
|
||||
|
||||
@Schema(description = "远程应用")
|
||||
private String remoteApp;
|
||||
|
||||
@Schema(description = "远程应用路径")
|
||||
private String remoteAppDir;
|
||||
|
||||
@Schema(description = "远程应用参数")
|
||||
private String remoteAppArgs;
|
||||
|
||||
}
|
||||
@@ -20,54 +20,29 @@
|
||||
* 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.common.session.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.visor.framework.desensitize.core.annotation.Desensitize;
|
||||
import org.dromara.visor.framework.desensitize.core.annotation.DesensitizeObject;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 终端连接参数
|
||||
* SSH 连接参数
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/12/26 15:47
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DesensitizeObject
|
||||
@Schema(name = "TerminalConnectDTO", description = "终端连接参数")
|
||||
public class TerminalConnectDTO {
|
||||
|
||||
@Schema(description = "logId")
|
||||
private Long logId;
|
||||
|
||||
@Schema(description = "连接类型")
|
||||
private String connectType;
|
||||
|
||||
@Schema(description = "hostId")
|
||||
private Long hostId;
|
||||
|
||||
@Schema(description = "hostName")
|
||||
private String hostName;
|
||||
|
||||
@Schema(description = "主机编码")
|
||||
private String hostCode;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String hostAddress;
|
||||
|
||||
@Schema(description = "主机端口")
|
||||
private Integer hostPort;
|
||||
|
||||
@Schema(description = "系统类型")
|
||||
private String osType;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(name = "SshConnectConfig", description = "SSH 连接参数")
|
||||
public class SshConnectConfig extends BaseConnectConfig {
|
||||
|
||||
@Schema(description = "超时时间")
|
||||
private Integer timeout;
|
||||
@@ -81,25 +56,15 @@ public class TerminalConnectDTO {
|
||||
@Schema(description = "文件内容编码")
|
||||
private String fileContentCharset;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Desensitize(toEmpty = true)
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "密钥id")
|
||||
private Long keyId;
|
||||
|
||||
@Desensitize(toEmpty = true)
|
||||
@Schema(description = "公钥文本")
|
||||
private String publicKey;
|
||||
|
||||
@Desensitize(toEmpty = true)
|
||||
@Schema(description = "私钥文本")
|
||||
private String privateKey;
|
||||
|
||||
@Desensitize(toEmpty = true)
|
||||
@Schema(description = "私钥密码")
|
||||
private String privateKeyPassword;
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.handler.host.jsch;
|
||||
package org.dromara.visor.common.session.ssh;
|
||||
|
||||
import cn.orionsec.kit.lang.exception.AuthenticationException;
|
||||
import cn.orionsec.kit.lang.exception.argument.InvalidArgumentException;
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.net.host.SessionHolder;
|
||||
@@ -31,9 +29,9 @@ import cn.orionsec.kit.net.host.SessionLogger;
|
||||
import cn.orionsec.kit.net.host.SessionStore;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.AppConst;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.session.SessionMessage;
|
||||
import org.dromara.visor.common.session.config.SshConnectConfig;
|
||||
import org.dromara.visor.common.utils.AesEncryptUtils;
|
||||
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -47,25 +45,22 @@ import java.util.Optional;
|
||||
@Slf4j
|
||||
public class SessionStores {
|
||||
|
||||
protected static final ThreadLocal<String> CURRENT_ADDRESS = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 打开 sessionStore
|
||||
*
|
||||
* @param conn conn
|
||||
* @param config config
|
||||
* @return sessionStore
|
||||
*/
|
||||
public static SessionStore openSessionStore(TerminalConnectDTO conn) {
|
||||
Long hostId = conn.getHostId();
|
||||
String address = conn.getHostAddress();
|
||||
String username = conn.getUsername();
|
||||
public static SessionStore openSessionStore(SshConnectConfig config) {
|
||||
Long hostId = config.getHostId();
|
||||
String address = config.getHostAddress();
|
||||
String username = config.getUsername();
|
||||
log.info("SessionStores-open-start hostId: {}, address: {}, username: {}", hostId, address, username);
|
||||
try {
|
||||
CURRENT_ADDRESS.set(address);
|
||||
// 创建会话
|
||||
SessionHolder sessionHolder = SessionHolder.create();
|
||||
sessionHolder.setLogger(SessionLogger.INFO);
|
||||
SessionStore session = createSessionStore(conn, sessionHolder);
|
||||
SessionStore session = createSessionStore(config, sessionHolder);
|
||||
// 设置版本
|
||||
session.getSession().setClientVersion("SSH-2.0-ORION_VISOR_V" + AppConst.VERSION);
|
||||
// 连接
|
||||
@@ -75,81 +70,48 @@ public class SessionStores {
|
||||
} catch (Exception e) {
|
||||
String message = e.getMessage();
|
||||
log.error("SessionStores-open-error hostId: {}, address: {}, username: {}, message: {}", hostId, address, username, message, e);
|
||||
throw Exceptions.app(getErrorMessage(e), e);
|
||||
} finally {
|
||||
CURRENT_ADDRESS.remove();
|
||||
throw Exceptions.app(SessionMessage.getErrorMessage(address, e), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 sessionStore
|
||||
*
|
||||
* @param conn conn
|
||||
* @param config config
|
||||
* @param sessionHolder sessionHolder
|
||||
* @return sessionStore
|
||||
*/
|
||||
private static SessionStore createSessionStore(TerminalConnectDTO conn, SessionHolder sessionHolder) {
|
||||
final boolean useKey = conn.getKeyId() != null;
|
||||
private static SessionStore createSessionStore(SshConnectConfig config, SessionHolder sessionHolder) {
|
||||
final boolean useKey = config.getKeyId() != null;
|
||||
// 使用密钥认证
|
||||
if (useKey) {
|
||||
// 加载密钥
|
||||
String publicKey = Optional.ofNullable(conn.getPublicKey())
|
||||
String publicKey = Optional.ofNullable(config.getPublicKey())
|
||||
.map(AesEncryptUtils::decryptAsString)
|
||||
.orElse(null);
|
||||
String privateKey = Optional.ofNullable(conn.getPrivateKey())
|
||||
String privateKey = Optional.ofNullable(config.getPrivateKey())
|
||||
.map(AesEncryptUtils::decryptAsString)
|
||||
.orElse(null);
|
||||
String password = Optional.ofNullable(conn.getPrivateKeyPassword())
|
||||
String password = Optional.ofNullable(config.getPrivateKeyPassword())
|
||||
.map(AesEncryptUtils::decryptAsString)
|
||||
.orElse(null);
|
||||
sessionHolder.addIdentityValue(String.valueOf(conn.getKeyId()),
|
||||
sessionHolder.addIdentityValue(String.valueOf(config.getKeyId()),
|
||||
privateKey,
|
||||
publicKey,
|
||||
password);
|
||||
}
|
||||
// 获取会话
|
||||
SessionStore session = sessionHolder.getSession(conn.getHostAddress(), conn.getHostPort(), conn.getUsername());
|
||||
SessionStore session = sessionHolder.getSession(config.getHostAddress(), config.getHostPort(), config.getUsername());
|
||||
// 使用密码认证
|
||||
if (!useKey) {
|
||||
String password = conn.getPassword();
|
||||
String password = config.getPassword();
|
||||
if (!Strings.isEmpty(password)) {
|
||||
session.password(AesEncryptUtils.decryptAsString(password));
|
||||
}
|
||||
}
|
||||
// 超时时间
|
||||
session.timeout(conn.getTimeout());
|
||||
session.timeout(config.getTimeout());
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误信息
|
||||
*
|
||||
* @param e e
|
||||
* @return errorMessage
|
||||
*/
|
||||
private static String getErrorMessage(Exception e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
String host = CURRENT_ADDRESS.get();
|
||||
String message = e.getMessage();
|
||||
if (Strings.contains(message, Const.TIMEOUT)) {
|
||||
// 连接超时
|
||||
return Strings.format(SessionMessage.CONNECTION_TIMEOUT, host);
|
||||
} else if (Exceptions.isCausedBy(e, AuthenticationException.class)) {
|
||||
// 认证失败
|
||||
return Strings.format(SessionMessage.AUTHENTICATION_FAILURE, host);
|
||||
} else if (Exceptions.isCausedBy(e, InvalidArgumentException.class)) {
|
||||
// 参数错误
|
||||
if (Strings.isBlank(message)) {
|
||||
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
} else {
|
||||
// 其他错误
|
||||
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
package org.dromara.visor.common.utils;
|
||||
|
||||
import cn.orionsec.kit.lang.constant.Const;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -43,6 +43,9 @@ public class SqlUtils {
|
||||
* @return limit
|
||||
*/
|
||||
public static String limit(Number limit) {
|
||||
if (limit == null) {
|
||||
return Const.EMPTY;
|
||||
}
|
||||
return Const.LIMIT + Const.SPACE + limit;
|
||||
}
|
||||
|
||||
@@ -54,6 +57,9 @@ public class SqlUtils {
|
||||
* @return limit
|
||||
*/
|
||||
public static String limit(Number offset, Number limit) {
|
||||
if (offset == null) {
|
||||
return limit(limit);
|
||||
}
|
||||
return Const.LIMIT + Const.SPACE + offset + Const.COMMA + limit;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ package org.dromara.visor.common.utils;
|
||||
import cn.orionsec.kit.lang.utils.Arrays1;
|
||||
import cn.orionsec.kit.lang.utils.io.Files1;
|
||||
import cn.orionsec.kit.spring.SpringHolder;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
@@ -159,4 +160,17 @@ public class Valid extends cn.orionsec.kit.lang.utils.Valid {
|
||||
return Files1.getPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查后缀
|
||||
*
|
||||
* @param file file
|
||||
* @param suffix suffix
|
||||
* @return file
|
||||
*/
|
||||
public static String checkSuffix(String file, String suffix) {
|
||||
Valid.notBlank(file);
|
||||
Valid.isTrue(file.toLowerCase().endsWith(Const.DOT + suffix), ErrorMessage.PLEASE_SELECT_SUFFIX_FILE, suffix);
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<url>https://github.com/dromara/orion-visor</url>
|
||||
|
||||
<properties>
|
||||
<revision>2.3.2</revision>
|
||||
<revision>2.4.0</revision>
|
||||
<spring.boot.version>2.7.17</spring.boot.version>
|
||||
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
||||
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
||||
@@ -34,6 +34,7 @@
|
||||
<mockito.inline.version>4.11.0</mockito.inline.version>
|
||||
<jedis.mock.version>1.0.7</jedis.mock.version>
|
||||
<podam.version>7.2.11.RELEASE</podam.version>
|
||||
<guacd.version>1.5.5</guacd.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -312,6 +313,13 @@
|
||||
<artifactId>podam</artifactId>
|
||||
<version>${podam.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- guacd -->
|
||||
<dependency>
|
||||
<groupId>org.apache.guacamole</groupId>
|
||||
<artifactId>guacamole-common</artifactId>
|
||||
<version>${guacd.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -122,4 +122,9 @@ public class OperatorLogModel implements RequestIdentity {
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@
|
||||
*/
|
||||
package org.dromara.visor.framework.mybatis.core.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
|
||||
@@ -41,10 +42,17 @@ import java.util.Date;
|
||||
* @since 2023/6/23 18:42
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BaseDO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
@@ -70,4 +78,4 @@ public class BaseDO implements Serializable {
|
||||
@TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.TINYINT)
|
||||
private Boolean deleted;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@
|
||||
package org.dromara.visor.framework.mybatis.core.generator;
|
||||
|
||||
import cn.orionsec.kit.lang.constant.Const;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.Systems;
|
||||
import cn.orionsec.kit.lang.utils.ansi.AnsiAppender;
|
||||
import cn.orionsec.kit.lang.utils.ansi.style.AnsiFont;
|
||||
import cn.orionsec.kit.lang.utils.ansi.style.color.AnsiForeground;
|
||||
@@ -32,6 +34,8 @@ import org.dromara.visor.framework.mybatis.core.generator.template.Table;
|
||||
import org.dromara.visor.framework.mybatis.core.generator.template.Template;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 代码生成器
|
||||
@@ -42,6 +46,8 @@ import java.io.File;
|
||||
*/
|
||||
public class CodeGenerators {
|
||||
|
||||
private static final Pattern ENV_VAR_PATTERN = Pattern.compile("\\$\\{([^:]+):([^}]+)\\}");
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 输出路径
|
||||
String outputDir = "D:/MP/";
|
||||
@@ -76,11 +82,6 @@ public class CodeGenerators {
|
||||
.disableUnitTest()
|
||||
.enableProviderApi()
|
||||
.vue("system", "message")
|
||||
.dict("messageClassify", "classify", "messageClassify")
|
||||
.comment("消息分类")
|
||||
.fields("NOTICE", "TODO")
|
||||
.labels("通知", "待办")
|
||||
.valueUseFields()
|
||||
.dict("messageType", "type", "messageType")
|
||||
.comment("消息类型")
|
||||
.fields("EXEC_FAILED", "UPLOAD_FAILED")
|
||||
@@ -94,9 +95,9 @@ public class CodeGenerators {
|
||||
// jdbc 配置 - 使用配置文件
|
||||
File yamlFile = new File("orion-visor-launch/src/main/resources/application-dev.yaml");
|
||||
YmlExt yaml = YmlExt.load(yamlFile);
|
||||
String url = yaml.getValue("spring.datasource.druid.url");
|
||||
String username = yaml.getValue("spring.datasource.druid.username");
|
||||
String password = yaml.getValue("spring.datasource.druid.password");
|
||||
String url = resolveConfigValue(yaml.getValue("spring.datasource.druid.url"));
|
||||
String username = resolveConfigValue(yaml.getValue("spring.datasource.druid.username"));
|
||||
String password = resolveConfigValue(yaml.getValue("spring.datasource.druid.password"));
|
||||
|
||||
// 执行
|
||||
runGenerator(outputDir, author,
|
||||
@@ -147,4 +148,31 @@ public class CodeGenerators {
|
||||
System.out.print(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析实际的配置
|
||||
*
|
||||
* @param value value
|
||||
* @return value
|
||||
*/
|
||||
private static String resolveConfigValue(String value) {
|
||||
if (Strings.isBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
Matcher matcher = ENV_VAR_PATTERN.matcher(value);
|
||||
StringBuffer resultString = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
// 环境变量名
|
||||
String envVar = matcher.group(1);
|
||||
// 默认值
|
||||
String defaultValue = matcher.group(2);
|
||||
// 获取环境变量的值
|
||||
String envValue = Systems.getEnv(envVar, defaultValue);
|
||||
// 替换占位符
|
||||
matcher.appendReplacement(resultString, Matcher.quoteReplacement(envValue));
|
||||
}
|
||||
// 处理结尾的剩余部分
|
||||
matcher.appendTail(resultString);
|
||||
return resultString.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
package org.dromara.visor.framework.mybatis.core.query;
|
||||
|
||||
import cn.orionsec.kit.lang.define.wrapper.DataGrid;
|
||||
import cn.orionsec.kit.lang.define.wrapper.IPageRequest;
|
||||
import cn.orionsec.kit.lang.define.wrapper.PageRequest;
|
||||
import cn.orionsec.kit.lang.define.wrapper.Pager;
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
@@ -33,11 +32,16 @@ import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.reflect.Classes;
|
||||
import cn.orionsec.kit.spring.SpringHolder;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.interfaces.Func;
|
||||
import com.baomidou.mybatisplus.core.conditions.interfaces.Join;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.entity.IOrderRequest;
|
||||
import org.dromara.visor.common.entity.IPageRequest;
|
||||
import org.dromara.visor.common.enums.BooleanBit;
|
||||
import org.dromara.visor.common.utils.SqlUtils;
|
||||
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
|
||||
|
||||
@@ -96,9 +100,9 @@ public class DataQuery<T> {
|
||||
return new DataQuery<>(dao, wrapper);
|
||||
}
|
||||
|
||||
public DataQuery<T> page(org.dromara.visor.common.entity.PageRequest page) {
|
||||
org.dromara.visor.common.entity.PageRequest pr = Valid.notNull(page, "page is null");
|
||||
this.page = new PageRequest(pr.getPage(), pr.getLimit());
|
||||
public DataQuery<T> page(IPageRequest request) {
|
||||
Valid.notNull(request, "page is null");
|
||||
this.page = new PageRequest(request.getPage(), request.getLimit());
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -130,15 +134,30 @@ public class DataQuery<T> {
|
||||
return then;
|
||||
}
|
||||
|
||||
public DataQuery<T> limit(IPageRequest page) {
|
||||
return this.last(Pager.of(page).getSql());
|
||||
public DataQuery<T> order(IOrderRequest request, SFunction<T, ?> column) {
|
||||
BooleanBit sorted = BooleanBit.of(request.getOrder());
|
||||
if (sorted == null) {
|
||||
return this;
|
||||
}
|
||||
return this.order(sorted.booleanValue(), column);
|
||||
}
|
||||
|
||||
public DataQuery<T> limit(int limit) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public DataQuery<T> order(boolean asc, SFunction<T, ?> column) {
|
||||
// 设置排序
|
||||
if (wrapper instanceof Func) {
|
||||
((Func<? extends T, SFunction<? extends T, ?>>) wrapper).orderBy(true, asc, column);
|
||||
return this;
|
||||
} else {
|
||||
throw Exceptions.argument("wrapper not implements Func");
|
||||
}
|
||||
}
|
||||
|
||||
public DataQuery<T> limit(Number limit) {
|
||||
return this.last(SqlUtils.limit(limit));
|
||||
}
|
||||
|
||||
public DataQuery<T> limit(int offset, int limit) {
|
||||
public DataQuery<T> limit(Number offset, Number limit) {
|
||||
return this.last(SqlUtils.limit(offset, limit));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class DomainFillUtils {
|
||||
*/
|
||||
public static void fillInsert(BaseDO baseDO) {
|
||||
Date now = new Date();
|
||||
String username = securityHolder.getLoginUsername();
|
||||
// 创建时间
|
||||
if (Objects.isNull(baseDO.getCreateTime())) {
|
||||
baseDO.setCreateTime(now);
|
||||
@@ -58,15 +59,13 @@ public class DomainFillUtils {
|
||||
if (Objects.isNull(baseDO.getUpdateTime())) {
|
||||
baseDO.setUpdateTime(now);
|
||||
}
|
||||
|
||||
Long userId = securityHolder.getLoginUserId();
|
||||
// 创建人
|
||||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getCreator())) {
|
||||
baseDO.setCreator(userId.toString());
|
||||
if (Objects.nonNull(username) && Objects.isNull(baseDO.getCreator())) {
|
||||
baseDO.setCreator(username);
|
||||
}
|
||||
// 更新人
|
||||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(userId.toString());
|
||||
if (Objects.nonNull(username) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(username);
|
||||
}
|
||||
// 逻辑删除字段
|
||||
if (Objects.isNull(baseDO.getDeleted())) {
|
||||
@@ -85,9 +84,9 @@ public class DomainFillUtils {
|
||||
baseDO.setUpdateTime(new Date());
|
||||
}
|
||||
// 更新人
|
||||
Long userId = securityHolder.getLoginUserId();
|
||||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(userId.toString());
|
||||
String username = securityHolder.getLoginUsername();
|
||||
if (Objects.nonNull(username) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(username);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.*;
|
||||
import java.math.*;
|
||||
@@ -38,7 +39,7 @@ import java.math.*;
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@@ -66,17 +67,8 @@ public class ${entity} {
|
||||
#if("$!field.comment" != "")
|
||||
@Schema(description = "${field.comment}")
|
||||
#end
|
||||
#if(${field.keyFlag})
|
||||
## 主键
|
||||
#if(${field.keyIdentityFlag})
|
||||
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
|
||||
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
|
||||
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
|
||||
#elseif(${field.convert})
|
||||
@TableId("${field.annotationColumnName}")
|
||||
#end
|
||||
## 普通字段
|
||||
#elseif(${field.fill})
|
||||
#if(${field.fill})
|
||||
## ----- 存在字段填充设置 -----
|
||||
#if(${field.convert})
|
||||
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
|
||||
|
||||
@@ -25,11 +25,9 @@ package ${currentPackage};
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import org.dromara.visor.common.entity.PageRequest;
|
||||
import org.dromara.visor.common.entity.BaseQueryRequest;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.*;
|
||||
import java.math.*;
|
||||
|
||||
/**
|
||||
* $!{table.comment} 查询请求对象
|
||||
@@ -44,7 +42,7 @@ import java.math.*;
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(name = "${type}QueryRequest", description = "$!{table.comment} 查询请求对象")
|
||||
public class ${type}QueryRequest extends PageRequest {
|
||||
public class ${type}QueryRequest extends BaseQueryRequest {
|
||||
|
||||
@Schema(description = "搜索")
|
||||
private String searchValue;
|
||||
|
||||
@@ -144,10 +144,11 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
@Override
|
||||
public List<${type}VO> get${type}List(${type}QueryRequest request) {
|
||||
// 条件
|
||||
LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request)
|
||||
.orderByDesc(${type}DO::getId);
|
||||
LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
|
||||
// 查询
|
||||
return ${typeLower}DAO.of(wrapper).list(${type}Convert.MAPPER::to);
|
||||
return ${typeLower}DAO.of(wrapper)
|
||||
.order(request, ${type}DO::getId)
|
||||
.list(${type}Convert.MAPPER::to);
|
||||
}
|
||||
#if($meta.enableCache)
|
||||
|
||||
@@ -176,12 +177,12 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
||||
@Override
|
||||
public DataGrid<${type}VO> get${type}Page(${type}QueryRequest request) {
|
||||
// 条件
|
||||
LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request)
|
||||
.orderByDesc(${type}DO::getId);
|
||||
LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
|
||||
// 查询
|
||||
return ${typeLower}DAO.of()
|
||||
.page(request)
|
||||
.wrapper(wrapper)
|
||||
.page(request)
|
||||
.order(request, ${type}DO::getId)
|
||||
.dataGrid(${type}Convert.MAPPER::to);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ SELECT @TYPE_KEY_ID:= id FROM dict_key WHERE key_name = 'operatorLogType' AND de
|
||||
INSERT INTO dict_value
|
||||
(`key_id`, `key_name`, `value`, `label`, `extra`, `sort`, `create_time`, `update_time`, `creator`, `updater`, `deleted`)
|
||||
VALUES
|
||||
(@MODULE_KEY_ID, 'operatorLogModule', '${package.ModuleName}:${typeHyphen}', '$!{table.comment}', '{}', @MODULE_KEY_MAX_SORT + 10, now(), now(), '1', '1', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:create', '创建$!{table.comment}', '{}', 10, now(), now(), '1', '1', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:update', '更新$!{table.comment}', '{}', 20, now(), now(), '1', '1', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:delete', '删除$!{table.comment}', '{}', 30, now(), now(), '1', '1', 0);
|
||||
(@MODULE_KEY_ID, 'operatorLogModule', '${package.ModuleName}:${typeHyphen}', '$!{table.comment}', '{}', @MODULE_KEY_MAX_SORT + 10, now(), now(), 'admin', 'admin', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:create', '创建$!{table.comment}', '{}', 10, now(), now(), 'admin', 'admin', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:update', '更新$!{table.comment}', '{}', 20, now(), now(), 'admin', 'admin', 0),
|
||||
(@TYPE_KEY_ID, 'operatorLogType', '${typeHyphen}:delete', '删除$!{table.comment}', '{}', 30, now(), now(), 'admin', 'admin', 0);
|
||||
#end
|
||||
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
@@ -23,7 +23,7 @@ VALUES
|
||||
INSERT INTO dict_key
|
||||
(`key_name`, `value_type`, `extra_schema`, `description`, `create_time`, `update_time`, `creator`, `updater`, `deleted`)
|
||||
VALUES
|
||||
('$enumEntity.value.keyName', 'STRING', '$enumEntity.value.extraSchema', '$enumEntity.value.comment', now(), now(), '1', '1', 0);
|
||||
('$enumEntity.value.keyName', 'STRING', '$enumEntity.value.extraSchema', '$enumEntity.value.comment', now(), now(), 'admin', 'admin', 0);
|
||||
|
||||
-- 设置临时配置项id
|
||||
SELECT @TMP_KEY_ID:=LAST_INSERT_ID();
|
||||
@@ -35,7 +35,7 @@ VALUES
|
||||
#set($count = $enumEntity.value.fields.size() - 1)
|
||||
#foreach($index in [0..$count])
|
||||
#set($sort = $index * 10 + 10)
|
||||
(@TMP_KEY_ID, '$enumEntity.value.keyName', '$enumEntity.value.values.get($index)', '$enumEntity.value.labels.get($index)', #if($enumEntity.value.extraJson.size() > $index)'$enumEntity.value.extraJson.get($index)'#else'{}'#end, $sort, now(), now(), '1', '1', 0)#if($foreach.hasNext),#else;#end
|
||||
(@TMP_KEY_ID, '$enumEntity.value.keyName', '$enumEntity.value.values.get($index)', '$enumEntity.value.labels.get($index)', #if($enumEntity.value.extraJson.size() > $index)'$enumEntity.value.extraJson.get($index)'#else'{}'#end, $sort, now(), now(), 'admin', 'admin', 0)#if($foreach.hasNext),#else;#end
|
||||
#end
|
||||
|
||||
#end
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
INSERT INTO system_menu
|
||||
(parent_id, name, type, sort, visible, status, cache, component, creator, updater, deleted)
|
||||
VALUES
|
||||
(0, '${table.comment}管理', 1, 10, 1, 1, 1, '${vue.moduleEntityFirstLower}Module', '1', '1', 0);
|
||||
(0, '${table.comment}管理', 1, 10, 1, 1, 1, '${vue.moduleEntityFirstLower}Module', 'admin', 'admin', 0);
|
||||
|
||||
-- 设置临时父菜单id
|
||||
SELECT @TMP_PARENT_ID:=LAST_INSERT_ID();
|
||||
@@ -13,7 +13,7 @@ SELECT @TMP_PARENT_ID:=LAST_INSERT_ID();
|
||||
INSERT INTO system_menu
|
||||
(parent_id, name, type, sort, visible, status, cache, component, creator, updater, deleted)
|
||||
VALUES
|
||||
(@TMP_PARENT_ID, '$table.comment', 2, 10, 1, 1, 1, '$vue.featureEntityFirstLower', '1', '1', 0);
|
||||
(@TMP_PARENT_ID, '$table.comment', 2, 10, 1, 1, 1, '$vue.featureEntityFirstLower', 'admin', 'admin', 0);
|
||||
|
||||
-- 设置临时子菜单id
|
||||
SELECT @TMP_SUB_ID:=LAST_INSERT_ID();
|
||||
@@ -22,7 +22,7 @@ SELECT @TMP_SUB_ID:=LAST_INSERT_ID();
|
||||
INSERT INTO system_menu
|
||||
(parent_id, name, permission, type, sort, creator, updater, deleted)
|
||||
VALUES
|
||||
(@TMP_SUB_ID, '查询$table.comment', '${package.ModuleName}:${typeHyphen}:query', 3, 10, '1', '1', 0),
|
||||
(@TMP_SUB_ID, '创建$table.comment', '${package.ModuleName}:${typeHyphen}:create', 3, 20, '1', '1', 0),
|
||||
(@TMP_SUB_ID, '修改$table.comment', '${package.ModuleName}:${typeHyphen}:update', 3, 30, '1', '1', 0),
|
||||
(@TMP_SUB_ID, '删除$table.comment', '${package.ModuleName}:${typeHyphen}:delete', 3, 40, '1', '1', 0);
|
||||
(@TMP_SUB_ID, '查询$table.comment', '${package.ModuleName}:${typeHyphen}:query', 3, 10, 'admin', 'admin', 0),
|
||||
(@TMP_SUB_ID, '创建$table.comment', '${package.ModuleName}:${typeHyphen}:create', 3, 20, 'admin', 'admin', 0),
|
||||
(@TMP_SUB_ID, '修改$table.comment', '${package.ModuleName}:${typeHyphen}:update', 3, 30, 'admin', 'admin', 0),
|
||||
(@TMP_SUB_ID, '删除$table.comment', '${package.ModuleName}:${typeHyphen}:delete', 3, 40, 'admin', 'admin', 0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DataGrid, Pagination } from '@/types/global';
|
||||
import type { TableData } from '@arco-design/web-vue/es/table/interface';
|
||||
import type { TableData } from '@arco-design/web-vue';
|
||||
import type { DataGrid, OrderDirection, Pagination } from '@/types/global';
|
||||
import axios from 'axios';
|
||||
import qs from 'query-string';
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface ${vue.featureEntity}UpdateRequest extends ${vue.featureEntity}C
|
||||
/**
|
||||
* ${table.comment}查询请求
|
||||
*/
|
||||
export interface ${vue.featureEntity}QueryRequest extends Pagination {
|
||||
export interface ${vue.featureEntity}QueryRequest extends Pagination, OrderDirection {
|
||||
searchValue?: string;
|
||||
#foreach($field in ${table.fields})
|
||||
#if("$field.propertyType" == "String" || "$field.propertyType" == "Date")
|
||||
|
||||
@@ -8,7 +8,7 @@ const $vue.moduleConst: AppRouteRecordRaw = {
|
||||
children: [
|
||||
{
|
||||
name: '$vue.featureEntityFirstLower',
|
||||
path: '/$vue.feature',
|
||||
path: '/$vue.module/$vue.feature',
|
||||
component: () => import('@/views/$vue.module/$vue.feature/index.vue'),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
search-input-placeholder="输入搜索值"
|
||||
:create-card-position="false"
|
||||
:loading="loading"
|
||||
:field-config="fieldConfig"
|
||||
:field-config="cardFieldConfig"
|
||||
:list="list"
|
||||
:pagination="pagination"
|
||||
:card-layout-cols="cardColLayout"
|
||||
:filter-count="filterCount"
|
||||
:add-permission="['${package.ModuleName}:${typeHyphen}:create']"
|
||||
:query-order="queryOrder"
|
||||
:fields-hook="fieldsHook"
|
||||
@add="emits('openAdd')"
|
||||
@reset="reset"
|
||||
@search="fetchCardData"
|
||||
@@ -74,16 +76,12 @@
|
||||
<!-- 修改 -->
|
||||
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:update']"
|
||||
@click="emits('openUpdate', record)">
|
||||
<span class="more-doption normal">
|
||||
<icon-edit /> 修改
|
||||
</span>
|
||||
<span class="more-doption normal">修改</span>
|
||||
</a-doption>
|
||||
<!-- 删除 -->
|
||||
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:delete']"
|
||||
@click="deleteRow(record.id)">
|
||||
<span class="more-doption error">
|
||||
<icon-delete /> 删除
|
||||
</span>
|
||||
<span class="more-doption error">删除</span>
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
@@ -94,17 +92,13 @@
|
||||
<!-- 修改 -->
|
||||
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:update']"
|
||||
@click="emits('openUpdate', record)">
|
||||
<span class="more-doption normal">
|
||||
<icon-edit /> 修改
|
||||
</span>
|
||||
<span class="more-doption normal">修改</span>
|
||||
</a-doption>
|
||||
<!-- 删除 -->
|
||||
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:delete']"
|
||||
class="span-red"
|
||||
@click="deleteRow(record.id)">
|
||||
<span class="more-doption error">
|
||||
<icon-delete /> 删除
|
||||
</span>
|
||||
<span class="more-doption error">删除</span>
|
||||
</a-doption>
|
||||
</template>
|
||||
</card-list>
|
||||
@@ -118,26 +112,29 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ${vue.featureEntity}QueryRequest, ${vue.featureEntity}QueryResponse } from '@/api/${vue.module}/${vue.feature}';
|
||||
import { useCardPagination, useCardColLayout } from '@/hooks/card';
|
||||
import { useCardPagination, useCardColLayout, useCardFieldConfig } from '@/hooks/card';
|
||||
import { computed, reactive, ref, onMounted } from 'vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { objectTruthKeyCount, resetObject } from '@/utils';
|
||||
import fieldConfig from '../types/card.fields';
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
import { #foreach($entry in ${dictMap.entrySet()})${entry.value.keyField}#if($foreach.hasNext), #end#end } from '../types/const';
|
||||
import { TableName, #foreach($entry in ${dictMap.entrySet()})${entry.value.keyField}#if($foreach.hasNext), #end#end } from '../types/const';
|
||||
#else
|
||||
import {} from '../types/const';
|
||||
import { TableName } from '../types/const';
|
||||
#end
|
||||
import { delete${vue.featureEntity}, get${vue.featureEntity}Page } from '@/api/${vue.module}/${vue.feature}';
|
||||
import { Message, Modal } from '@arco-design/web-vue';
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
import { useDictStore } from '@/store';
|
||||
#end
|
||||
import { useQueryOrder, ASC } from '@/hooks/query-order';
|
||||
|
||||
const emits = defineEmits(['openAdd', 'openUpdate']);
|
||||
|
||||
const cardColLayout = useCardColLayout();
|
||||
const pagination = useCardPagination();
|
||||
const queryOrder = useQueryOrder(TableName, ASC);
|
||||
const { cardFieldConfig, fieldsHook } = useCardFieldConfig(TableName, fieldConfig);
|
||||
const { loading, setLoading } = useLoading();
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
const { toOptions, getDictValue } = useDictStore();
|
||||
@@ -198,7 +195,7 @@
|
||||
const doFetchCardData = async (request: ${vue.featureEntity}QueryRequest) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data } = await get${vue.featureEntity}Page(request);
|
||||
const { data } = await get${vue.featureEntity}Page(queryOrder.markOrderly(request));
|
||||
list.value = data.rows;
|
||||
pagination.total = data.total;
|
||||
pagination.current = request.page;
|
||||
|
||||
@@ -75,6 +75,11 @@
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
#end
|
||||
<!-- 调整 -->
|
||||
<table-adjust :columns="columns"
|
||||
:columns-hook="columnsHook"
|
||||
:query-order="queryOrder"
|
||||
@query="fetchTableData" />
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
@@ -87,7 +92,7 @@
|
||||
#end
|
||||
ref="tableRef"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:columns="tableColumns"
|
||||
#if($vue.enableRowSelection)
|
||||
:row-selection="rowSelection"
|
||||
#end
|
||||
@@ -146,25 +151,29 @@
|
||||
import useLoading from '@/hooks/loading';
|
||||
import columns from '../types/table.columns';
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
import { #foreach($entry in ${dictMap.entrySet()})${entry.value.keyField}#if($foreach.hasNext), #end#end } from '../types/const';
|
||||
import { TableName, #foreach($entry in ${dictMap.entrySet()})${entry.value.keyField}#if($foreach.hasNext), #end#end } from '../types/const';
|
||||
#else
|
||||
import {} from '../types/const';
|
||||
import { TableName } from '../types/const';
|
||||
#end
|
||||
#if($vue.enableRowSelection)
|
||||
import { useTablePagination, useRowSelection } from '@/hooks/table';
|
||||
import { useTablePagination, useRowSelection, useTableColumns } from '@/hooks/table';
|
||||
#else
|
||||
import { useTablePagination } from '@/hooks/table';
|
||||
import { useTablePagination, useTableColumns } from '@/hooks/table';
|
||||
#end
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
import { useDictStore } from '@/store';
|
||||
#end
|
||||
import { useQueryOrder, ASC } from '@/hooks/query-order';
|
||||
import TableAdjust from '@/components/app/table-adjust/index.vue';
|
||||
|
||||
const emits = defineEmits(['openAdd', 'openUpdate']);
|
||||
|
||||
const pagination = useTablePagination();
|
||||
#if($vue.enableRowSelection)
|
||||
const rowSelection = useRowSelection();
|
||||
#end
|
||||
const pagination = useTablePagination();
|
||||
const queryOrder = useQueryOrder(TableName, ASC);
|
||||
const { tableColumns, columnsHook } = useTableColumns(TableName, columns);
|
||||
const { loading, setLoading } = useLoading();
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
const { toOptions, getDictValue } = useDictStore();
|
||||
@@ -227,7 +236,7 @@
|
||||
const doFetchTableData = async (request: ${vue.featureEntity}QueryRequest) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data } = await get${vue.featureEntity}Page(request);
|
||||
const { data } = await get${vue.featureEntity}Page(queryOrder.markOrderly(request));
|
||||
tableRenderData.value = data.rows;
|
||||
pagination.total = data.total;
|
||||
pagination.current = request.page;
|
||||
|
||||
@@ -3,13 +3,14 @@ import { dateFormat } from '@/utils';
|
||||
|
||||
const fieldConfig = {
|
||||
rowGap: '10px',
|
||||
labelSpan: 8,
|
||||
labelSpan: 6,
|
||||
minHeight: '22px',
|
||||
fields: [
|
||||
{
|
||||
label: 'id',
|
||||
dataIndex: 'id',
|
||||
slotName: 'id',
|
||||
default: true,
|
||||
}, #foreach($field in ${table.fields})#if("$!field.propertyName" != "id"){
|
||||
label: '${field.comment}',
|
||||
dataIndex: '${field.propertyName}',
|
||||
@@ -21,6 +22,7 @@ const fieldConfig = {
|
||||
return record.${field.propertyName} && dateFormat(new Date(record.${field.propertyName}));
|
||||
},
|
||||
#end
|
||||
default: true,
|
||||
}, #end#end{
|
||||
label: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export const TABLE_NAME = '$table.name';
|
||||
|
||||
#if($dictMap.entrySet().size() > 0)
|
||||
#foreach($enumEntity in $dictMap.entrySet())
|
||||
// $enumEntity.value.comment
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import type { TableColumnData } from '@arco-design/web-vue';
|
||||
import { dateFormat } from '@/utils';
|
||||
|
||||
const columns = [
|
||||
@@ -9,6 +9,7 @@ const columns = [
|
||||
width: 68,
|
||||
align: 'left',
|
||||
fixed: 'left',
|
||||
default: true,
|
||||
}, #foreach($field in ${table.fields})#if("$!field.propertyName" != "id"){
|
||||
title: '${field.comment}',
|
||||
dataIndex: '${field.propertyName}',
|
||||
@@ -24,6 +25,7 @@ const columns = [
|
||||
return record.${field.propertyName} && dateFormat(new Date(record.${field.propertyName}));
|
||||
},
|
||||
#end
|
||||
default: true,
|
||||
}, #end#end{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
|
||||
@@ -31,8 +31,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.function.Supplier;
|
||||
@@ -68,12 +68,10 @@ public class OrionNoRedisAutoConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
public JedisConnectionFactory jedisConnectionFactory(RedisServer redisServer) {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setHostName(redisServer.getHost());
|
||||
factory.setPort(redisServer.getBindPort());
|
||||
factory.setUsePool(true);
|
||||
factory.setPoolConfig(new JedisPoolConfig());
|
||||
return factory;
|
||||
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
|
||||
config.setHostName(redisServer.getHost());
|
||||
config.setPort(redisServer.getBindPort());
|
||||
return new JedisConnectionFactory(config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,8 @@ public class CacheBarriers {
|
||||
|
||||
public static final GenericsBarrier<Map<?, ?>> MAP = GenericsAnonymousMapBarrier.create(Const.NONE_ID, Const.NONE_ID);
|
||||
|
||||
public static final GenericsBarrier<Map<?, ?>> STRING_MAP = GenericsAnonymousMapBarrier.create(Const.NONE_ID.toString(), Const.NONE_ID);
|
||||
|
||||
/**
|
||||
* 创建屏障对象 防止穿透
|
||||
*
|
||||
|
||||
@@ -230,7 +230,7 @@ public class OrionSecurityAutoConfiguration {
|
||||
return httpSecurity
|
||||
// 开启跨域
|
||||
.cors().and()
|
||||
// 因为不使用session 禁用CSRF
|
||||
// 因为不使用 session 禁用 CSRF
|
||||
.csrf().disable()
|
||||
// 基于 token 机制所以不需要 session
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
|
||||
@@ -45,4 +45,9 @@ public class SecurityHolderDelegate implements SecurityHolder {
|
||||
return SecurityUtils.getLoginUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoginUsername() {
|
||||
return SecurityUtils.getLoginUsername();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,27 @@ public class StaticResourceAuthorizeRequestsCustomizer extends AuthorizeRequests
|
||||
@Override
|
||||
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
|
||||
// 静态资源可匿名访问
|
||||
registry.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll();
|
||||
registry.antMatchers(HttpMethod.GET,
|
||||
"/*.html",
|
||||
"/*.css",
|
||||
"/*.js",
|
||||
"/*.gz",
|
||||
"/*.ico",
|
||||
"/*.jpg",
|
||||
"/*.png",
|
||||
"/*.svg",
|
||||
"/*.json",
|
||||
"/*.webmanifest",
|
||||
"/**/*.html",
|
||||
"/**/*.css",
|
||||
"/**/*.js",
|
||||
"/**/*.gz",
|
||||
"/**/*.ico",
|
||||
"/**/*.jpg",
|
||||
"/**/*.png",
|
||||
"/**/*.svg",
|
||||
"/**/*.json"
|
||||
).permitAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@ public class OrionMockBeanTestConfiguration {
|
||||
public Long getLoginUserId() {
|
||||
return DEFAULT.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoginUsername() {
|
||||
return DEFAULT.getUsername();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ package org.dromara.visor.framework.test.core.base;
|
||||
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.dromara.visor.common.configuration.SpringConfiguration;
|
||||
import org.dromara.visor.framework.datasource.configuration.OrionDataSourceAutoConfiguration;
|
||||
import org.dromara.visor.framework.mybatis.configuration.OrionMybatisAutoConfiguration;
|
||||
import org.dromara.visor.framework.redis.configuration.OrionRedisAutoConfiguration;
|
||||
@@ -57,6 +58,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class BaseUnitTest {
|
||||
|
||||
@Import({
|
||||
// spring
|
||||
SpringConfiguration.class,
|
||||
// mock
|
||||
OrionMockBeanTestConfiguration.class,
|
||||
OrionMockRedisTestConfiguration.class,
|
||||
@@ -74,7 +77,6 @@ public class BaseUnitTest {
|
||||
RedisAutoConfiguration.class,
|
||||
RedissonAutoConfiguration.class,
|
||||
})
|
||||
// TODO
|
||||
public static class Application {
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
"description": "是否为演示模式.",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "orion.prefix",
|
||||
"type": "java.lang.String",
|
||||
"description": "项目前缀."
|
||||
},
|
||||
{
|
||||
"name": "orion.api.prefix",
|
||||
"type": "java.lang.String",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.framework.websocket.core.constant;
|
||||
|
||||
/**
|
||||
* ws 服务端关闭 code
|
||||
* <p>
|
||||
* > 2999 && < 5000
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2021/6/16 15:18
|
||||
*/
|
||||
public interface CloseCode {
|
||||
|
||||
/**
|
||||
* code
|
||||
*
|
||||
* @return code
|
||||
*/
|
||||
int getCode();
|
||||
|
||||
/**
|
||||
* reason
|
||||
*
|
||||
* @return reason
|
||||
*/
|
||||
String getReason();
|
||||
|
||||
}
|
||||
@@ -22,27 +22,36 @@
|
||||
*/
|
||||
package org.dromara.visor.framework.websocket.core.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* ws 服务端关闭 code
|
||||
* ws 关闭码
|
||||
* <p>
|
||||
* > 2999 && < 5000
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2021/6/16 15:18
|
||||
* @since 2024/7/31 17:41
|
||||
*/
|
||||
public interface WsCloseCode {
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum WsCloseCode implements CloseCode {
|
||||
|
||||
/**
|
||||
* code
|
||||
*
|
||||
* @return code
|
||||
* 初始化失败
|
||||
*/
|
||||
int getCode();
|
||||
INIT_ERROR(3000, "init error"),
|
||||
|
||||
/**
|
||||
* reason
|
||||
*
|
||||
* @return reason
|
||||
* 会话已关闭
|
||||
*/
|
||||
String getReason();
|
||||
SESSION_CLOSED(3100, "session closed"),
|
||||
|
||||
;
|
||||
|
||||
private final int code;
|
||||
|
||||
private final String reason;
|
||||
|
||||
}
|
||||
|
||||
@@ -22,18 +22,23 @@
|
||||
*/
|
||||
package org.dromara.visor.framework.websocket.core.utils;
|
||||
|
||||
import cn.orionsec.kit.lang.constant.StandardHttpHeader;
|
||||
import cn.orionsec.kit.lang.utils.Exceptions;
|
||||
import cn.orionsec.kit.lang.utils.Threads;
|
||||
import cn.orionsec.kit.lang.utils.io.Streams;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.framework.websocket.core.constant.WsCloseCode;
|
||||
import org.dromara.visor.framework.websocket.core.constant.CloseCode;
|
||||
import org.dromara.visor.framework.websocket.core.session.WebSocketSyncSession;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* websocket 工具类
|
||||
@@ -132,18 +137,54 @@ public class WebSockets {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置子协议
|
||||
*
|
||||
* @param request request
|
||||
* @param response response
|
||||
*/
|
||||
public static void setSubProtocols(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
List<String> subProtocols = request.getHeaders().get(StandardHttpHeader.SEC_WEBSOCKET_PROTOCOL);
|
||||
if (subProtocols != null) {
|
||||
response.getHeaders().put(StandardHttpHeader.SEC_WEBSOCKET_PROTOCOL, subProtocols);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session session
|
||||
*/
|
||||
public static void close(WebSocketSession session) {
|
||||
if (!session.isOpen()) {
|
||||
return;
|
||||
}
|
||||
Streams.close(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session session
|
||||
* @param code code
|
||||
*/
|
||||
public static void close(WebSocketSession session, WsCloseCode code) {
|
||||
public static void close(WebSocketSession session, CloseCode code) {
|
||||
close(session, code.getCode(), code.getReason());
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session session
|
||||
* @param code code
|
||||
* @param reason reason
|
||||
*/
|
||||
public static void close(WebSocketSession session, int code, String reason) {
|
||||
if (!session.isOpen()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
session.close(new CloseStatus(code.getCode(), code.getReason()));
|
||||
session.close(new CloseStatus(code, reason));
|
||||
} catch (Exception e) {
|
||||
log.error("websocket close failure", e);
|
||||
}
|
||||
|
||||
@@ -23,13 +23,26 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- starter -->
|
||||
<!-- spring boot starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- modules -->
|
||||
<!-- 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 service -->
|
||||
<dependency>
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-module-infra-service</artifactId>
|
||||
@@ -40,6 +53,16 @@
|
||||
<artifactId>orion-visor-module-asset-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-module-exec-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-module-terminal-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- framework starter -->
|
||||
<dependency>
|
||||
@@ -112,8 +135,12 @@
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<resources>
|
||||
<!-- 应用配置过滤 -->
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>*.yaml</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
@@ -42,7 +42,11 @@ import java.util.Optional;
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/19 16:55
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {"org.dromara.visor.launch", "org.dromara.visor.module"})
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"org.dromara.visor.launch",
|
||||
"org.dromara.visor.common",
|
||||
"org.dromara.visor.module"
|
||||
})
|
||||
public class LaunchApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
spring:
|
||||
datasource:
|
||||
druid:
|
||||
url: jdbc:mysql://127.0.0.1:3306/orion_visor?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true
|
||||
username: root
|
||||
password: Data@123456
|
||||
url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:orion_visor}?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true
|
||||
username: ${MYSQL_USER:root}
|
||||
password: ${MYSQL_PASSWORD:Data@123456}
|
||||
initial-size: 0
|
||||
min-idle: 1
|
||||
max-active: 5
|
||||
stat-view-servlet:
|
||||
enabled: false
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: Data@123456
|
||||
host: ${REDIS_HOST:127.0.0.1}
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: ${REDIS_PASSWORD:Data@123456}
|
||||
redisson:
|
||||
threads: 2
|
||||
netty-threads: 2
|
||||
@@ -24,6 +24,11 @@ spring:
|
||||
server:
|
||||
enabled: false
|
||||
|
||||
guacd:
|
||||
host: ${GUACD_HOST:127.0.0.1}
|
||||
port: ${GUACD_PORT:4822}
|
||||
drive-path: ${GUACD_DRIVE_PATH:/home/guacd/drive}
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
enabled-by-default: false
|
||||
@@ -33,7 +38,7 @@ management:
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
# sql 日志打印
|
||||
# 日志打印
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
no:
|
||||
|
||||
@@ -41,6 +41,11 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
|
||||
guacd:
|
||||
host: ${GUACD_HOST:127.0.0.1}
|
||||
port: ${GUACD_PORT:4822}
|
||||
drive-path: ${GUACD_DRIVE_PATH:/usr/share/guacd/drive}
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
enabled-by-default: true
|
||||
|
||||
@@ -157,65 +157,22 @@ logging:
|
||||
level:
|
||||
org.dromara.visor.launch.controller.BootstrapController: INFO
|
||||
|
||||
# 应用配置
|
||||
app:
|
||||
# 认证配置
|
||||
authentication:
|
||||
# 是否允许多端登录
|
||||
allow-multi-device: true
|
||||
# 是否允许凭证续签
|
||||
allow-refresh: true
|
||||
# 凭证续签最大次数
|
||||
max-refresh-count: 3
|
||||
# 登录失败发送站内信阈值
|
||||
login-failed-send-threshold: 3
|
||||
# 登录失败锁定次数
|
||||
login-failed-lock-count: 5
|
||||
# 登录失败锁定时间 (分)
|
||||
login-failed-lock-time: 30
|
||||
# tracker 配置
|
||||
tracker:
|
||||
# 加载偏移量 (行)
|
||||
offset: 300
|
||||
# 延迟时间 (ms)
|
||||
delay: 100
|
||||
# 文件未找到等待次数
|
||||
wait-times: 100
|
||||
# sftp 配置
|
||||
sftp:
|
||||
# 上传文件时 文件存在是否备份
|
||||
upload-present-backup: true
|
||||
# 备份文件名称
|
||||
backup-file-name: bk_${fileName}_${timestamp}
|
||||
# 执行日志
|
||||
exec-log:
|
||||
# 是否拼接 ansi 执行状态日志
|
||||
append-ansi: true
|
||||
# 自动清理配置
|
||||
auto-clear:
|
||||
# 批量执行日志
|
||||
exec-log:
|
||||
enabled: false
|
||||
keep-period: 30
|
||||
# 终端连接日志
|
||||
terminal-connect-log:
|
||||
enabled: false
|
||||
keep-period: 30
|
||||
|
||||
# orion framework config
|
||||
orion:
|
||||
# 版本
|
||||
version: @revision@
|
||||
# 是否为演示模式
|
||||
demo: false
|
||||
# 前缀
|
||||
prefix: /orion-visor
|
||||
api:
|
||||
# 公共 api 前缀
|
||||
prefix: /orion-visor/api
|
||||
prefix: ${orion.prefix}/api
|
||||
# 是否允许跨域
|
||||
cors: true
|
||||
websocket:
|
||||
# 公共 websocket 前缀
|
||||
prefix: /orion-visor/keep-alive
|
||||
prefix: ${orion.prefix}/keep-alive
|
||||
# 1MB
|
||||
binary-buffer-size: 1048576
|
||||
# 1MB
|
||||
@@ -239,6 +196,12 @@ orion:
|
||||
asset:
|
||||
group: "asset - 资产模块"
|
||||
path: "asset"
|
||||
exec:
|
||||
group: "exec - 执行模块"
|
||||
path: "exec"
|
||||
terminal:
|
||||
group: "terminal - 终端模块"
|
||||
path: "terminal"
|
||||
logging:
|
||||
# 全局日志打印
|
||||
printer:
|
||||
@@ -251,6 +214,7 @@ orion:
|
||||
field:
|
||||
ignore:
|
||||
- password,beforePassword,newPassword,useNewPassword,publicKey,privateKey,privateKeyPassword
|
||||
- accessKey,secretKey
|
||||
- metrics
|
||||
desensitize:
|
||||
storage:
|
||||
|
||||
@@ -39,19 +39,20 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class ReplaceVersion {
|
||||
|
||||
private static final String TARGET_VERSION = "2.3.1";
|
||||
private static final String TARGET_VERSION = "2.3.9";
|
||||
|
||||
private static final String REPLACE_VERSION = "2.3.2";
|
||||
private static final String REPLACE_VERSION = "2.4.0";
|
||||
|
||||
private static final String PATH = new File("").getAbsolutePath();
|
||||
|
||||
private static final String[] DOCKER_FILES = new String[]{
|
||||
"docker/push.sh",
|
||||
"docker/adminer/build.sh",
|
||||
"docker/adminer/build.sh",
|
||||
"docker/mysql/build.sh",
|
||||
"docker/redis/build.sh",
|
||||
"docker/guacd/build.sh",
|
||||
"docker/service/build.sh",
|
||||
"docker/ui/build.sh",
|
||||
"docker-compose.yml",
|
||||
"docker-compose-testing.yml"
|
||||
};
|
||||
|
||||
@@ -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.asset.api;
|
||||
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.dromara.visor.module.asset.enums.HostTypeEnum;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 资产模块 授权数据对外服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/12 16:13
|
||||
*/
|
||||
public interface AssetAuthorizedDataApi {
|
||||
|
||||
/**
|
||||
* 获取用户已授权&配置已启用的主机id 查询角色
|
||||
*
|
||||
* @param userId userId
|
||||
* @param type type
|
||||
* @return hostId
|
||||
*/
|
||||
List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type);
|
||||
|
||||
/**
|
||||
* 查询用户已授权并且启用的主机
|
||||
*
|
||||
* @param userId userId
|
||||
* @param type type
|
||||
* @return group
|
||||
*/
|
||||
List<HostDTO> getUserAuthorizedHostList(Long userId, HostTypeEnum type);
|
||||
|
||||
}
|
||||
@@ -20,26 +20,35 @@
|
||||
* 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.asset.api;
|
||||
|
||||
import org.dromara.visor.module.asset.handler.host.terminal.model.TerminalBasePayload;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 终端消息处理器
|
||||
* 主机 对外服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/12/29 18:53
|
||||
* @since 2024/10/12 16:14
|
||||
*/
|
||||
public interface ITerminalHandler<T extends TerminalBasePayload> {
|
||||
public interface HostApi {
|
||||
|
||||
/**
|
||||
* 处理消息
|
||||
* 通过 id 查询
|
||||
*
|
||||
* @param channel channel
|
||||
* @param payload payload
|
||||
* @param id id
|
||||
* @return row
|
||||
*/
|
||||
void handle(WebSocketSession channel, T payload);
|
||||
HostDTO selectById(Long id);
|
||||
|
||||
/**
|
||||
* 通过 id 查询
|
||||
*
|
||||
* @param idList idList
|
||||
* @return rows
|
||||
*/
|
||||
List<HostDTO> selectByIdList(List<Long> idList);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.api;
|
||||
|
||||
import org.dromara.visor.common.session.config.RdpConnectConfig;
|
||||
import org.dromara.visor.common.session.config.SshConnectConfig;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
|
||||
/**
|
||||
* 主机连接 对外服务
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/12 23:53
|
||||
*/
|
||||
public interface HostConnectApi {
|
||||
|
||||
/**
|
||||
* 获取 SSH 连接配置
|
||||
*
|
||||
* @param hostId hostId
|
||||
* @return session
|
||||
*/
|
||||
SshConnectConfig getSshConnectConfig(Long hostId);
|
||||
|
||||
/**
|
||||
* 使用用户配置获取 SSH 连接配置
|
||||
*
|
||||
* @param hostId hostId
|
||||
* @param userId userId
|
||||
* @return session
|
||||
*/
|
||||
SshConnectConfig getSshConnectConfig(Long hostId, Long userId);
|
||||
|
||||
/**
|
||||
* 使用用户配置获取 SSH 连接配置
|
||||
*
|
||||
* @param host host
|
||||
* @param userId userId
|
||||
* @return session
|
||||
*/
|
||||
SshConnectConfig getSshConnectConfig(HostDTO host, Long userId);
|
||||
|
||||
/**
|
||||
* 获取 RDP 连接配置
|
||||
*
|
||||
* @param hostId hostId
|
||||
* @return session
|
||||
*/
|
||||
RdpConnectConfig getRdpConnectConfig(Long hostId);
|
||||
|
||||
/**
|
||||
* 使用用户配置获取 RDP 连接配置
|
||||
*
|
||||
* @param hostId hostId
|
||||
* @param userId userId
|
||||
* @return session
|
||||
*/
|
||||
RdpConnectConfig getRdpConnectConfig(Long hostId, Long userId);
|
||||
|
||||
/**
|
||||
* 使用用户配置获取 RDP 连接配置
|
||||
*
|
||||
* @param host host
|
||||
* @param userId userId
|
||||
* @return session
|
||||
*/
|
||||
RdpConnectConfig getRdpConnectConfig(HostDTO host, Long userId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.entity.dto.host;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 主机基本信息 业务响应对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-11 14:16
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "HostBaseDTO", description = "主机基本信息 业务响应对象")
|
||||
public class HostBaseDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "主机类型")
|
||||
private String types;
|
||||
|
||||
@Schema(description = "系统类型")
|
||||
private String osType;
|
||||
|
||||
@Schema(description = "系统架构")
|
||||
private String archType;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "主机编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "主机端口")
|
||||
private Integer port;
|
||||
|
||||
}
|
||||
@@ -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.asset.entity.dto.host;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 主机 业务对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-11 14:16
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "HostDTO", description = "主机 业务对象")
|
||||
public class HostDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "主机类型")
|
||||
private String types;
|
||||
|
||||
@Schema(description = "系统类型")
|
||||
private String osType;
|
||||
|
||||
@Schema(description = "系统架构")
|
||||
private String archType;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "主机编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "主机端口")
|
||||
private Integer port;
|
||||
|
||||
@Schema(description = "主机状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date updateTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "修改人")
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "是否收藏")
|
||||
private Boolean favorite;
|
||||
|
||||
@Schema(description = "分组 id")
|
||||
private Set<Long> groupIdList;
|
||||
|
||||
@Schema(description = "别名")
|
||||
private String alias;
|
||||
|
||||
@Schema(description = "颜色")
|
||||
private String color;
|
||||
|
||||
/**
|
||||
* 转为 base
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public HostBaseDTO toBase() {
|
||||
return HostBaseDTO.builder()
|
||||
.id(this.id)
|
||||
.types(this.types)
|
||||
.name(this.name)
|
||||
.code(this.code)
|
||||
.address(this.address)
|
||||
.port(this.port)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.entity.dto.host;
|
||||
|
||||
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.handler.data.model.GenericsDataModel;
|
||||
import org.dromara.visor.common.security.UpdatePasswordAction;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 主机 RDP 配置
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/9/13 16:18
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "HostRdpConfigDTO", description = "主机 RDP 配置业务对象")
|
||||
public class HostRdpConfigDTO implements GenericsDataModel, UpdatePasswordAction {
|
||||
|
||||
@NotNull
|
||||
@Min(value = 1)
|
||||
@Max(value = 65535)
|
||||
@Schema(description = "主机端口")
|
||||
private Integer port;
|
||||
|
||||
@Size(max = 128)
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "认证方式")
|
||||
private String authType;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "身份id")
|
||||
private Long identityId;
|
||||
|
||||
@Schema(description = "RDP 版本是否大于8.1")
|
||||
private Boolean versionGt81;
|
||||
|
||||
@Schema(description = "时区")
|
||||
private String timezone;
|
||||
|
||||
@Schema(description = "键盘布局")
|
||||
private String keyboardLayout;
|
||||
|
||||
@Schema(description = "剪切板规范")
|
||||
private String clipboardNormalize;
|
||||
|
||||
@Schema(description = "域")
|
||||
private String domain;
|
||||
|
||||
@Schema(description = "预连接id")
|
||||
private String preConnectionId;
|
||||
|
||||
@Schema(description = "预连接数据")
|
||||
private String preConnectionBlob;
|
||||
|
||||
@Schema(description = "远程应用")
|
||||
private String remoteApp;
|
||||
|
||||
@Schema(description = "远程应用路径")
|
||||
private String remoteAppDir;
|
||||
|
||||
@Schema(description = "远程应用参数")
|
||||
private String remoteAppArgs;
|
||||
|
||||
@Schema(description = "是否使用新密码 仅参数")
|
||||
private Boolean useNewPassword;
|
||||
|
||||
@Schema(description = "是否已设置密码 仅返回")
|
||||
private Boolean hasPassword;
|
||||
|
||||
}
|
||||
@@ -20,8 +20,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.handler.host.config.model;
|
||||
package org.dromara.visor.module.asset.entity.dto.host;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@@ -42,73 +43,58 @@ import javax.validation.constraints.*;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class HostSshConfigModel implements GenericsDataModel, UpdatePasswordAction {
|
||||
@Schema(name = "HostSshConfigDTO", description = "主机 SSH 配置业务对象")
|
||||
public class HostSshConfigDTO implements GenericsDataModel, UpdatePasswordAction {
|
||||
|
||||
@NotNull
|
||||
@Min(value = 1)
|
||||
@Max(value = 65535)
|
||||
@Schema(description = "主机端口")
|
||||
private Integer port;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Size(max = 128)
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 认证方式
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "认证方式")
|
||||
private String authType;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 身份id
|
||||
*/
|
||||
@Schema(description = "身份id")
|
||||
private Long identityId;
|
||||
|
||||
/**
|
||||
* 密钥id
|
||||
*/
|
||||
@Schema(description = "密钥id")
|
||||
private Long keyId;
|
||||
|
||||
/**
|
||||
* 连接超时时间
|
||||
*/
|
||||
@NotNull
|
||||
@Min(value = 1)
|
||||
@Max(value = 100000)
|
||||
@Schema(description = "连接超时时间")
|
||||
private Integer connectTimeout;
|
||||
|
||||
/**
|
||||
* SSH输出编码
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "SSH输出编码")
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* 文件名称编码
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "文件名称编码")
|
||||
private String fileNameCharset;
|
||||
|
||||
/**
|
||||
* 文件内容编码
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(max = 12)
|
||||
@Schema(description = "文件内容编码")
|
||||
private String fileContentCharset;
|
||||
|
||||
/**
|
||||
* 是否使用新密码 仅参数
|
||||
*/
|
||||
@Schema(description = "是否使用新密码 仅参数")
|
||||
private Boolean useNewPassword;
|
||||
|
||||
/**
|
||||
* 是否已设置密码 仅返回
|
||||
*/
|
||||
@Schema(description = "是否已设置密码 仅返回")
|
||||
private Boolean hasPassword;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 主机系统架构类型
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/4/16 21:58
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum HostArchTypeEnum {
|
||||
|
||||
/**
|
||||
* X86_64
|
||||
*/
|
||||
AMD64,
|
||||
|
||||
/**
|
||||
* arm64
|
||||
*/
|
||||
ARM64,
|
||||
|
||||
;
|
||||
|
||||
public boolean is(String type) {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
return type.equalsIgnoreCase(this.name());
|
||||
}
|
||||
|
||||
public static HostArchTypeEnum of(String type) {
|
||||
if (type == null) {
|
||||
return AMD64;
|
||||
}
|
||||
type = type.toUpperCase();
|
||||
for (HostArchTypeEnum value : values()) {
|
||||
if (value.name().equals(type) || type.contains(value.name())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return AMD64;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,40 +46,33 @@ public enum HostOsTypeEnum {
|
||||
*/
|
||||
WINDOWS(".cmd"),
|
||||
|
||||
/**
|
||||
* darwin
|
||||
*/
|
||||
DARWIN(".sh"),
|
||||
|
||||
;
|
||||
|
||||
private final String scriptSuffix;
|
||||
|
||||
public boolean is(String type) {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
return type.equalsIgnoreCase(this.name());
|
||||
}
|
||||
|
||||
public static HostOsTypeEnum of(String type) {
|
||||
if (type == null) {
|
||||
return LINUX;
|
||||
}
|
||||
type = type.toUpperCase();
|
||||
for (HostOsTypeEnum value : values()) {
|
||||
if (value.name().equals(type)) {
|
||||
if (value.name().equals(type) || type.contains(value.name())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return LINUX;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为 linux 系统
|
||||
*
|
||||
* @param type type
|
||||
* @return isLinux
|
||||
*/
|
||||
public static boolean isLinux(String type) {
|
||||
return LINUX.name().equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为 windows 系统
|
||||
*
|
||||
* @param type type
|
||||
* @return isWindows
|
||||
*/
|
||||
public static boolean isWindows(String type) {
|
||||
return WINDOWS.name().equals(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.enums;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostRdpConfigDTO;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostSshConfigDTO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 主机类型
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/12 18:12
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum HostTypeEnum {
|
||||
|
||||
/**
|
||||
* SSH
|
||||
*/
|
||||
SSH(HostSshConfigDTO.class),
|
||||
|
||||
/**
|
||||
* RDP
|
||||
*/
|
||||
RDP(HostRdpConfigDTO.class),
|
||||
|
||||
;
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
public static HostTypeEnum of(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
for (HostTypeEnum value : values()) {
|
||||
if (value.name().equals(type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<String> split(String types) {
|
||||
if (types == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return Arrays.stream(types.split(Const.COMMA))
|
||||
.map(HostTypeEnum::of)
|
||||
.filter(Objects::nonNull)
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T parse(String config) {
|
||||
return (T) JSON.parseObject(config, this.clazz);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,11 @@
|
||||
<artifactId>orion-visor-module-asset-provider</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-module-exec-provider</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- framework starter -->
|
||||
<dependency>
|
||||
@@ -82,6 +87,10 @@
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-spring-boot-starter-job</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.visor</groupId>
|
||||
<artifactId>orion-visor-spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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.asset.api.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.module.asset.api.AssetAuthorizedDataApi;
|
||||
import org.dromara.visor.module.asset.convert.HostProviderConvert;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.dromara.visor.module.asset.entity.vo.AuthorizedHostWrapperVO;
|
||||
import org.dromara.visor.module.asset.enums.HostTypeEnum;
|
||||
import org.dromara.visor.module.asset.service.AssetAuthorizedDataService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 资产模块 授权数据对外服务实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/12 18:14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AssetAuthorizedDataApiImpl implements AssetAuthorizedDataApi {
|
||||
|
||||
@Resource
|
||||
private AssetAuthorizedDataService assetAuthorizedDataService;
|
||||
|
||||
@Override
|
||||
public List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type) {
|
||||
return assetAuthorizedDataService.getUserAuthorizedEnabledHostId(userId, type.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HostDTO> getUserAuthorizedHostList(Long userId, HostTypeEnum type) {
|
||||
AuthorizedHostWrapperVO wrapper = assetAuthorizedDataService.getUserAuthorizedHost(userId, type.name());
|
||||
return wrapper.getHostList()
|
||||
.stream()
|
||||
.map(HostProviderConvert.MAPPER::to)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.api.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.module.asset.api.HostApi;
|
||||
import org.dromara.visor.module.asset.convert.HostProviderConvert;
|
||||
import org.dromara.visor.module.asset.dao.HostDAO;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 主机 对外服务实现类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/12 18:27
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class HostApiImpl implements HostApi {
|
||||
|
||||
@Resource
|
||||
private HostDAO hostDAO;
|
||||
|
||||
@Override
|
||||
public HostDTO selectById(Long id) {
|
||||
return HostProviderConvert.MAPPER.to(hostDAO.selectById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HostDTO> selectByIdList(List<Long> idList) {
|
||||
if (Lists.isEmpty(idList)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
return hostDAO.selectBatchIds(idList)
|
||||
.stream()
|
||||
.map(HostProviderConvert.MAPPER::to)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.asset.api.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.session.config.RdpConnectConfig;
|
||||
import org.dromara.visor.common.session.config.SshConnectConfig;
|
||||
import org.dromara.visor.module.asset.api.HostConnectApi;
|
||||
import org.dromara.visor.module.asset.convert.HostProviderConvert;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.dromara.visor.module.asset.service.HostConnectService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 主机连接 对外服务实现
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/10/13 0:03
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class HostConnectApiImpl implements HostConnectApi {
|
||||
|
||||
@Resource
|
||||
private HostConnectService hostConnectService;
|
||||
|
||||
@Override
|
||||
public SshConnectConfig getSshConnectConfig(Long hostId) {
|
||||
return hostConnectService.getSshConnectConfig(hostId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SshConnectConfig getSshConnectConfig(Long hostId, Long userId) {
|
||||
return hostConnectService.getSshConnectConfig(hostId, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SshConnectConfig getSshConnectConfig(HostDTO host, Long userId) {
|
||||
return hostConnectService.getSshConnectConfig(HostProviderConvert.MAPPER.to(host), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RdpConnectConfig getRdpConnectConfig(Long hostId) {
|
||||
return hostConnectService.getRdpConnectConfig(hostId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RdpConnectConfig getRdpConnectConfig(Long hostId, Long userId) {
|
||||
return hostConnectService.getRdpConnectConfig(hostId, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RdpConnectConfig getRdpConnectConfig(HostDTO host, Long userId) {
|
||||
return hostConnectService.getRdpConnectConfig(HostProviderConvert.MAPPER.to(host), userId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public class AssetAuthorizedDataServiceController {
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/current-host")
|
||||
@Operation(summary = "查询当前用户已授权的主机")
|
||||
public AuthorizedHostWrapperVO getCurrentAuthorizedHost(@RequestParam("type") String type) {
|
||||
public AuthorizedHostWrapperVO getCurrentAuthorizedHost(@RequestParam(value = "type", required = false) String type) {
|
||||
return assetAuthorizedDataService.getUserAuthorizedHost(SecurityUtils.getLoginUserId(), type);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.asset.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.framework.biz.operator.log.core.annotation.OperatorLog;
|
||||
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||
import org.dromara.visor.framework.web.core.annotation.DemoDisableApi;
|
||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||
import org.dromara.visor.module.asset.define.operator.HostOperatorType;
|
||||
import org.dromara.visor.module.asset.entity.request.host.HostConfigQueryRequest;
|
||||
import org.dromara.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
|
||||
import org.dromara.visor.module.asset.service.HostConfigService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 主机 api
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-9-11 14:16
|
||||
*/
|
||||
@Tag(name = "asset - 主机配置服务")
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestWrapper
|
||||
@RestController
|
||||
@RequestMapping("/asset/host-config")
|
||||
public class HostConfigController {
|
||||
|
||||
@Resource
|
||||
private HostConfigService hostConfigService;
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(HostOperatorType.UPDATE_CONFIG)
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新主机配置")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
|
||||
public Integer updateHostConfig(@Validated @RequestBody HostConfigUpdateRequest request) {
|
||||
return hostConfigService.updateHostConfig(request);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/get")
|
||||
@Operation(summary = "查询主机配置")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:query')")
|
||||
public Object getHostConfig(@Validated @RequestBody HostConfigQueryRequest request) {
|
||||
return hostConfigService.getHostConfigView(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,8 +35,8 @@ 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.HostOperatorType;
|
||||
import org.dromara.visor.module.asset.entity.request.host.*;
|
||||
import org.dromara.visor.module.asset.entity.vo.HostConfigVO;
|
||||
import org.dromara.visor.module.asset.entity.vo.HostVO;
|
||||
import org.dromara.visor.module.asset.service.HostConnectService;
|
||||
import org.dromara.visor.module.asset.service.HostService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -63,6 +63,9 @@ public class HostController {
|
||||
@Resource
|
||||
private HostService hostService;
|
||||
|
||||
@Resource
|
||||
private HostConnectService hostConnectService;
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(HostOperatorType.CREATE)
|
||||
@PostMapping("/create")
|
||||
@@ -81,6 +84,17 @@ public class HostController {
|
||||
return hostService.updateHostById(request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(HostOperatorType.CREATE)
|
||||
@PostMapping("/copy")
|
||||
@Operation(summary = "复制主机")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:create')")
|
||||
public Long copyHost(@Validated @RequestBody HostUpdateRequest request) {
|
||||
Long id = request.getId();
|
||||
request.setId(null);
|
||||
return hostService.copyHost(id, request);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(HostOperatorType.UPDATE_STATUS)
|
||||
@PutMapping("/update-status")
|
||||
@@ -91,12 +105,12 @@ public class HostController {
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@OperatorLog(HostOperatorType.UPDATE_CONFIG)
|
||||
@PutMapping("/update-config")
|
||||
@Operation(summary = "更新主机配置")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
|
||||
public Integer updateHostConfig(@Validated @RequestBody HostUpdateConfigRequest request) {
|
||||
return hostService.updateHostConfig(request);
|
||||
@OperatorLog(HostOperatorType.UPDATE_SPEC)
|
||||
@PutMapping("/update-spec")
|
||||
@Operation(summary = "修改主机规格信息")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:update')")
|
||||
public Integer updateHostSpec(@Validated @RequestBody HostExtraUpdateRequest request) {
|
||||
return hostService.updateHostSpec(request);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@@ -108,15 +122,6 @@ public class HostController {
|
||||
return hostService.getHostById(id);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/get-config")
|
||||
@Operation(summary = "查询主机配置")
|
||||
@Parameter(name = "id", description = "id", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:query')")
|
||||
public HostConfigVO getHostConfig(@RequestParam("id") Long id) {
|
||||
return hostService.getHostConfig(id);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询主机")
|
||||
@@ -138,7 +143,7 @@ public class HostController {
|
||||
@PostMapping("/count")
|
||||
@Operation(summary = "查询主机数量")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host:query')")
|
||||
public Long getHostExportCount(@Validated @RequestBody HostQueryRequest request) {
|
||||
public Long getHostCount(@Validated @RequestBody HostQueryRequest request) {
|
||||
return hostService.getHostCount(request);
|
||||
}
|
||||
|
||||
@@ -162,5 +167,14 @@ public class HostController {
|
||||
return hostService.deleteHostByIdList(idList);
|
||||
}
|
||||
|
||||
@DemoDisableApi
|
||||
@PostMapping("/test-connect")
|
||||
@Operation(summary = "测试主机连接")
|
||||
@PreAuthorize("@ss.hasAnyPermission('asset:host:update', 'asset:host:update-config')")
|
||||
public Boolean testHostConnect(@Validated @RequestBody HostTestConnectRequest request) {
|
||||
hostConnectService.testHostConnect(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Valid;
|
||||
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.host.HostExtraQueryRequest;
|
||||
import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest;
|
||||
import org.dromara.visor.module.asset.handler.host.extra.HostExtraItemEnum;
|
||||
import org.dromara.visor.module.asset.service.HostExtraService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -61,20 +63,15 @@ public class HostExtraController {
|
||||
@Operation(summary = "获取主机拓展信息")
|
||||
@Parameter(name = "hostId", description = "hostId", required = true)
|
||||
@Parameter(name = "item", description = "item", required = true)
|
||||
public Map<String, Object> getHostExtra(@RequestParam("hostId") Long hostId, @RequestParam("item") String item) {
|
||||
return hostExtraService.getHostExtra(hostId, item);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/list")
|
||||
@Operation(summary = "获取多个主机拓展信息")
|
||||
public Map<String, Map<String, Object>> getHostExtraList(@Validated @RequestBody HostExtraQueryRequest request) {
|
||||
return hostExtraService.getHostExtraList(request);
|
||||
public Map<String, Object> getHostExtraView(@RequestParam("hostId") Long hostId, @RequestParam("item") String item) {
|
||||
return hostExtraService.getHostExtraView(hostId, item);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改主机拓展信息")
|
||||
public Integer updateHostExtra(@Validated @RequestBody HostExtraUpdateRequest request) {
|
||||
HostExtraItemEnum item = Valid.valid(HostExtraItemEnum::of, request.getItem());
|
||||
Valid.isTrue(item.isUserExtra(), ErrorMessage.PARAM_ERROR);
|
||||
return hostExtraService.updateHostExtra(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public class HostGroupController {
|
||||
@OperatorLog(HostGroupOperatorType.RENAME)
|
||||
@PutMapping("/rename")
|
||||
@Operation(summary = "修改名称")
|
||||
@PreAuthorize("@ss.hasPermission('asset:host-group:update')")
|
||||
@PreAuthorize("@ss.hasAnyPermission('asset:host-group:update', 'asset:host:query')")
|
||||
public Integer updateHostGroupName(@Validated @RequestBody DataGroupRenameDTO request) {
|
||||
return hostGroupService.updateHostGroupName(request);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class HostGroupController {
|
||||
@GetMapping("/rel-list")
|
||||
@Operation(summary = "查询分组内主机")
|
||||
@Parameter(name = "groupId", description = "groupId", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('asset:host-group:update')")
|
||||
@PreAuthorize("@ss.hasAnyPermission('asset:host-group:update', 'asset:host:query')")
|
||||
public Set<Long> queryHostGroupRel(@RequestParam("groupId") Long groupId) {
|
||||
return hostGroupService.queryHostGroupRel(groupId);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user