Compare commits
96 Commits
dev-applic
...
dev-1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ec839d18 | ||
|
|
a6a9e5c2e7 | ||
|
|
9b92bacd86 | ||
|
|
e68a16a500 | ||
|
|
fe0a344ec4 | ||
|
|
661af68cbf | ||
|
|
705f8c7c71 | ||
|
|
524e9f8880 | ||
|
|
24d928d7ba | ||
|
|
59e01f71e5 | ||
|
|
95e950ecd0 | ||
|
|
dc5f2ebb74 | ||
|
|
9a85280ca2 | ||
|
|
46d9614603 | ||
|
|
910027435b | ||
|
|
d9964d52ba | ||
|
|
a10e37bbd1 | ||
|
|
dc45c3d62e | ||
|
|
89c5a94715 | ||
|
|
00f6bf65a1 | ||
|
|
c4bdd18974 | ||
|
|
d18baeab7c | ||
|
|
e17feb87b2 | ||
|
|
d281ee05d4 | ||
|
|
2df576ab10 | ||
|
|
9706eee814 | ||
|
|
ed5dd781b4 | ||
|
|
b80b0fdf43 | ||
|
|
55d374fa98 | ||
|
|
daf362aa0b | ||
|
|
160c7e9117 | ||
|
|
b0db257f81 | ||
|
|
6698bc6a66 | ||
|
|
584cce1629 | ||
|
|
0b08291d7c | ||
|
|
0c59be48f9 | ||
|
|
120265c6ac | ||
|
|
79ca9b3b02 | ||
|
|
3ec0a33d3a | ||
|
|
b037e46f8e | ||
|
|
df01d6a618 | ||
|
|
ce1b53a657 | ||
|
|
6f9a738a37 | ||
|
|
575dbdab52 | ||
|
|
69f0946775 | ||
|
|
d1f0ec1a58 | ||
|
|
ac391799de | ||
|
|
af7635d508 | ||
|
|
11e1b85ba5 | ||
|
|
70c8d98d99 | ||
|
|
b7e3048e64 | ||
|
|
5d77111530 | ||
|
|
6bed4ad795 | ||
|
|
77c62ca317 | ||
|
|
00a647eb35 | ||
|
|
bba9a543b0 | ||
|
|
90301ae75e | ||
|
|
bec7e90774 | ||
|
|
0f4c12b38e | ||
|
|
6ec9ba3981 | ||
|
|
b6fa061aae | ||
|
|
ee091445a4 | ||
|
|
db049e78f4 | ||
|
|
a9251f238c | ||
|
|
64f5a46928 | ||
|
|
f4b22ff416 | ||
|
|
fec4beed2d | ||
|
|
1d0b3c6c9b | ||
|
|
d75d109b19 | ||
|
|
8f810462ef | ||
|
|
7a936b6187 | ||
|
|
96c9b992af | ||
|
|
7137793307 | ||
|
|
df66435492 | ||
|
|
a8e496b073 | ||
|
|
737613d2ee | ||
|
|
66214087d5 | ||
|
|
9e206505e5 | ||
|
|
09622b5ed3 | ||
|
|
16fc3a4bc2 | ||
|
|
9051cd3fac | ||
|
|
5bae5dfdd3 | ||
|
|
bbbe71ae33 | ||
|
|
fda9a1b2b1 | ||
|
|
46e2b0632f | ||
|
|
8e835e4ea3 | ||
|
|
1db74870e0 | ||
|
|
3d95329f01 | ||
|
|
7c99ed06bb | ||
|
|
11396c6dd1 | ||
|
|
a1f2bede19 | ||
|
|
13a9d8f674 | ||
|
|
756d8c5cd1 | ||
|
|
6ea9ad9413 | ||
|
|
6bb44b101d | ||
|
|
bf2ee90390 |
12
pom.xml
12
pom.xml
@@ -179,6 +179,18 @@
|
|||||||
<version>2.12.0</version>
|
<version>2.12.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jgit</groupId>
|
||||||
|
<artifactId>org.eclipse.jgit</artifactId>
|
||||||
|
<version>7.0.0.202409031743-r</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package net.geedge.asw.common.config;
|
||||||
|
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class FreeMarkerConfig {
|
||||||
|
|
||||||
|
@Value("${asw.template.path:static}")
|
||||||
|
private String templatePath;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FreeMarkerConfigurationFactoryBean factoryBean() {
|
||||||
|
FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean = new FreeMarkerConfigurationFactoryBean();
|
||||||
|
// 设置 FreeMarker 模板位置
|
||||||
|
boolean exist = T.FileUtil.exist(templatePath);
|
||||||
|
templatePath = exist ? templatePath : "classpath:" + templatePath;
|
||||||
|
freeMarkerConfigurationFactoryBean.setTemplateLoaderPath(templatePath);
|
||||||
|
|
||||||
|
// 其他配置
|
||||||
|
Properties settings = new Properties();
|
||||||
|
settings.setProperty("default_encoding", "utf-8");
|
||||||
|
settings.setProperty("number_format", "0.##");
|
||||||
|
|
||||||
|
freeMarkerConfigurationFactoryBean.setFreemarkerSettings(settings);
|
||||||
|
return freeMarkerConfigurationFactoryBean;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
package net.geedge.asw.common.config;
|
package net.geedge.asw.common.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
|
||||||
|
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
import java.util.UUID;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
public class MybatisPlusConfig {
|
public class MybatisPlusConfig {
|
||||||
@@ -19,4 +23,29 @@ public class MybatisPlusConfig {
|
|||||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));//如果配置多个插件,切记分页最后添加
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));//如果配置多个插件,切记分页最后添加
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public IdentifierGenerator identifierGenerator() {
|
||||||
|
return new IdentifierGenerator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Number nextId(Object entity) {
|
||||||
|
return DefaultIdentifierGenerator.getInstance().nextId(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义 UUID 生成格式,带有中划线,示例格式:c2ce91d1-d1f4-4629-aae4-414df36d87ca
|
||||||
|
*
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String nextUUID(Object entity) {
|
||||||
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
return (new UUID(random.nextLong(), random.nextLong())).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
101
src/main/java/net/geedge/asw/common/config/Query.java
Normal file
101
src/main/java/net/geedge/asw/common/config/Query.java
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package net.geedge.asw.common.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询参数
|
||||||
|
*/
|
||||||
|
public class Query {
|
||||||
|
|
||||||
|
private Class clz;
|
||||||
|
|
||||||
|
public Class<? extends Object> getClz() {
|
||||||
|
return clz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClz(Class clz) {
|
||||||
|
this.clz = clz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Query(Class clz) {
|
||||||
|
this.clz = clz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page getPage(Map<String, Object> params) {
|
||||||
|
return this.getPage(params, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
|
||||||
|
//分页参数
|
||||||
|
long curPage = 1;
|
||||||
|
long limit = Constants.PAGESIZE;
|
||||||
|
|
||||||
|
if(params.get(Constants.PAGE) != null){
|
||||||
|
curPage = Long.parseLong((String)params.get(Constants.PAGE));
|
||||||
|
}
|
||||||
|
if(params.get(Constants.LIMIT) != null){
|
||||||
|
limit = Long.parseLong((String)params.get(Constants.LIMIT));
|
||||||
|
if(limit == -1){
|
||||||
|
limit = Long.MAX_VALUE;
|
||||||
|
curPage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//分页对象
|
||||||
|
Page page = new Page(curPage, limit);
|
||||||
|
|
||||||
|
//分页参数
|
||||||
|
params.put(Constants.PAGE, page);
|
||||||
|
|
||||||
|
//排序字段 orderBy=id
|
||||||
|
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
|
||||||
|
String orderField = SQLFilter.sqlInject((String)params.get(Constants.ORDER));
|
||||||
|
|
||||||
|
if (StrUtil.isNotEmpty(orderField)) {
|
||||||
|
boolean matcheFlag = orderField.trim().matches("-?[a-zA-Z_.-]+");
|
||||||
|
if (!matcheFlag) {
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取表名
|
||||||
|
Class<?> clz = this.getClz();
|
||||||
|
String tableName = "";
|
||||||
|
if (clz != null) {
|
||||||
|
TableName table = this.getClz().getAnnotation(TableName.class);
|
||||||
|
tableName = table.value();
|
||||||
|
}
|
||||||
|
// 通过表名获取排序字段映射
|
||||||
|
Map<String, String> columnAliasMap = Constants.TABLE_NAME_ORDER_FIELD_MAPPING.get(tableName);
|
||||||
|
columnAliasMap = T.MapUtil.isEmpty(columnAliasMap) ? new HashMap<>():columnAliasMap;
|
||||||
|
if (orderField.startsWith("-")) {
|
||||||
|
orderField = orderField.substring(1, orderField.length());
|
||||||
|
orderField = columnAliasMap.get(orderField) != null ? columnAliasMap.get(orderField) : orderField;
|
||||||
|
return page.addOrder(OrderItem.desc(orderField));
|
||||||
|
} else {
|
||||||
|
orderField = columnAliasMap.get(orderField) != null ? columnAliasMap.get(orderField) : orderField;
|
||||||
|
return page.addOrder(OrderItem.asc(orderField));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认排序
|
||||||
|
if (StrUtil.isNotEmpty(defaultOrderField)) {
|
||||||
|
if (isAsc) {
|
||||||
|
return page.addOrder(OrderItem.asc(defaultOrderField));
|
||||||
|
} else {
|
||||||
|
return page.addOrder(OrderItem.desc(defaultOrderField));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/net/geedge/asw/common/config/SQLFilter.java
Normal file
49
src/main/java/net/geedge/asw/common/config/SQLFilter.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.geedge.asw.common.config;
|
||||||
|
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL过滤
|
||||||
|
*
|
||||||
|
* @author Mark sunlightcs@gmail.com
|
||||||
|
*/
|
||||||
|
public class SQLFilter {
|
||||||
|
|
||||||
|
private static String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
|
||||||
|
|
||||||
|
private static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL注入过滤
|
||||||
|
* @param str 待验证的字符串
|
||||||
|
*/
|
||||||
|
public static String sqlInject(String str) {
|
||||||
|
if (T.StrUtil.isBlank(str)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//转换成小写
|
||||||
|
String str1 = str.toLowerCase();
|
||||||
|
|
||||||
|
String s = "";
|
||||||
|
if (str1.startsWith("-")) {
|
||||||
|
s = str1.substring(1);
|
||||||
|
} else {
|
||||||
|
s = str1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlPattern.matcher(s).matches()) {
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/main/java/net/geedge/asw/common/config/job/JobConfig.java
Normal file
103
src/main/java/net/geedge/asw/common/config/job/JobConfig.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package net.geedge.asw.common.config.job;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.job.JobEnvironmentStatusChecker;
|
||||||
|
import net.geedge.asw.module.runner.job.JobPlaybookExecResultChecker;
|
||||||
|
import net.geedge.asw.module.runner.job.JobPlaybookExecutor;
|
||||||
|
import net.geedge.asw.module.sys.service.ISysConfigService;
|
||||||
|
import org.quartz.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class JobConfig {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
private static final String JOB_NAME_PREFIX = "ASW_JOB";
|
||||||
|
private static final String JOB_DEFAULT_GROUP = "SYSTEM";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get job key
|
||||||
|
* job_name=ASW_JOB_{name}
|
||||||
|
* group_name=SYSTEM
|
||||||
|
*/
|
||||||
|
private static JobKey getJobKey(String name) {
|
||||||
|
String jobName = T.StrUtil.concat(true, JOB_NAME_PREFIX, "_", name);
|
||||||
|
return new JobKey(jobName, JOB_DEFAULT_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Scheduler scheduler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysConfigService sysConfigService;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail JobEnvironmentStatusChecker() {
|
||||||
|
return JobBuilder.newJob(JobEnvironmentStatusChecker.class)
|
||||||
|
.withIdentity(getJobKey(JobEnvironmentStatusChecker.class.getSimpleName()))
|
||||||
|
.storeDurably()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail JobPlaybookExecutor() {
|
||||||
|
return JobBuilder.newJob(JobPlaybookExecutor.class)
|
||||||
|
.withIdentity(getJobKey(JobPlaybookExecutor.class.getSimpleName()))
|
||||||
|
.storeDurably()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail JobPlaybookExecResultChecker() {
|
||||||
|
return JobBuilder.newJob(JobPlaybookExecResultChecker.class)
|
||||||
|
.withIdentity(getJobKey(JobPlaybookExecResultChecker.class.getSimpleName()))
|
||||||
|
.storeDurably()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() throws SchedulerException {
|
||||||
|
// JobEnvironmentStatusChecker
|
||||||
|
createCronScheduleJob(JobEnvironmentStatusChecker(), environment.getProperty("asw.cron.JobEnvironmentStatusChecker", "0 0/1 * * * ? *"));
|
||||||
|
createCronScheduleJob(JobPlaybookExecutor(), environment.getProperty("asw.cron.JobPlaybookExecutor", "0 0/1 * * * ? *"));
|
||||||
|
createCronScheduleJob(JobPlaybookExecResultChecker(), environment.getProperty("asw.cron.JobPlaybookExecResultChecker", "0/30 * * * * ?"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create cron schedule job
|
||||||
|
* 先删后增
|
||||||
|
*/
|
||||||
|
private void createCronScheduleJob(JobDetail jobDetail, String cronExpression) throws SchedulerException {
|
||||||
|
JobKey key = jobDetail.getKey();
|
||||||
|
|
||||||
|
boolean jobExists = scheduler.checkExists(key);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[createCronScheduleJob] [key: {}] [exists: {}]", key.toString(), jobExists);
|
||||||
|
}
|
||||||
|
if (jobExists) {
|
||||||
|
scheduler.deleteJob(key);
|
||||||
|
log.debug("[createCronScheduleJob] [key: {}] [deleted]", key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String timezone = sysConfigService.getValue("timezone");
|
||||||
|
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone(timezone));
|
||||||
|
|
||||||
|
CronTrigger cronTrigger = TriggerBuilder.newTrigger()
|
||||||
|
.forJob(jobDetail)
|
||||||
|
.withSchedule(cronScheduleBuilder)
|
||||||
|
.build();
|
||||||
|
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package net.geedge.asw.common.config.websocket;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.*;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.WebSocket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EnvironmentNovncWebSocketHandler extends TextWebSocketHandler {
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env id
|
||||||
|
*/
|
||||||
|
private String envId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session
|
||||||
|
*/
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user id
|
||||||
|
*/
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
public EnvironmentNovncWebSocketHandler(IEnvironmentService environmentService, IEnvironmentSessionService environmentSessionService) {
|
||||||
|
this.environmentService = environmentService;
|
||||||
|
this.environmentSessionService = environmentSessionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFieldVal(WebSocketSession session) {
|
||||||
|
this.envId = (String) session.getAttributes().get("envId");
|
||||||
|
this.sessionId = (String) session.getAttributes().get("sessionId");
|
||||||
|
this.userId = (String) session.getAttributes().get("userId");
|
||||||
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.put(sessionId, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
super.afterConnectionEstablished(session);
|
||||||
|
this.initFieldVal(session);
|
||||||
|
// token
|
||||||
|
if (T.StrUtil.isEmpty(userId)) {
|
||||||
|
log.warn("Websocket token authentication failed");
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Websocket token authentication failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// env session
|
||||||
|
EnvironmentSessionEntity environmentSession = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (environmentSession == null) {
|
||||||
|
log.warn("environment session does not exist. session id: {}", sessionId);
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment session does not exist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("WebSocket connectioned. after connection established open environment begin... environment id: {}", envId);
|
||||||
|
EnvironmentEntity deviceEntity = environmentService.queryInfo(envId);
|
||||||
|
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
||||||
|
|
||||||
|
String urlStr = String.format("%s%s", paramJSONObject.getStr("url"), Constants.ENV_NOVNC_WEBSOCKET_PATH);
|
||||||
|
urlStr = urlStr.replace("http", "ws");
|
||||||
|
WebSocket webSocket = null;
|
||||||
|
try {
|
||||||
|
HttpClient client = HttpClient.newHttpClient();
|
||||||
|
webSocket = client.newWebSocketBuilder()
|
||||||
|
.buildAsync(URI.create(urlStr), new WebSocketListener(session))
|
||||||
|
.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "Environment WebSocket connectioned. after connection established open environment error. session id: {}", sessionId);
|
||||||
|
if (ObjectUtil.isNotNull(webSocket)) {
|
||||||
|
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
if (session != null) {
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment WebSocket connectioned. after connection established open environment error!"));
|
||||||
|
IoUtil.close(session);
|
||||||
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("[afterConnectionEstablished] [environment server: {}]", T.JSONUtil.toJsonStr(paramJSONObject));
|
||||||
|
session.getAttributes().put("envWebsocket", webSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket 监听器实现
|
||||||
|
private static class WebSocketListener implements WebSocket.Listener {
|
||||||
|
private WebSocketSession session;
|
||||||
|
|
||||||
|
public WebSocketListener(WebSocketSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// env -> asw
|
||||||
|
session.sendMessage(new BinaryMessage(data, true));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return WebSocket.Listener.super.onBinary(webSocket, data, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
|
||||||
|
log.info("Environment webSocket connection closed, Status: " + statusCode + ", Reason: " + reason);
|
||||||
|
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
|
||||||
|
try {
|
||||||
|
// asw -> env
|
||||||
|
WebSocket envSocket = (WebSocket) session.getAttributes().get("envWebsocket");
|
||||||
|
if (envSocket != null) {
|
||||||
|
envSocket.sendBinary(message.getPayload(), true);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[handleBinaryMessage] [error]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||||
|
log.info("[afterConnectionClosed] [WebSocket connection closed] [websocket uri: {}]", session.getUri());
|
||||||
|
WebSocket envWebsocket = (WebSocket) session.getAttributes().get("envWebsocket");
|
||||||
|
if (envWebsocket != null) {
|
||||||
|
envWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
super.afterConnectionClosed(session, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package net.geedge.asw.common.config.websocket;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.WebSocket;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EnvironmentTerminalWebSocketHandler extends TextWebSocketHandler {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env id
|
||||||
|
*/
|
||||||
|
private String envId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session
|
||||||
|
*/
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user id
|
||||||
|
*/
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
public EnvironmentTerminalWebSocketHandler(IEnvironmentService environmentService, IEnvironmentSessionService environmentSessionService) {
|
||||||
|
this.environmentService = environmentService;
|
||||||
|
this.environmentSessionService = environmentSessionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFieldVal(WebSocketSession session) {
|
||||||
|
this.envId = (String) session.getAttributes().get("envId");
|
||||||
|
this.sessionId = (String) session.getAttributes().get("sessionId");
|
||||||
|
this.userId = (String) session.getAttributes().get("userId");
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.put(sessionId, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
super.afterConnectionEstablished(session);
|
||||||
|
|
||||||
|
this.initFieldVal(session);
|
||||||
|
// token
|
||||||
|
if (T.StrUtil.isEmpty(userId)) {
|
||||||
|
log.warn("Websocket token authentication failed");
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Websocket token authentication failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// env session
|
||||||
|
EnvironmentSessionEntity environmentSession = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (environmentSession == null) {
|
||||||
|
log.warn("environment session does not exist. session id: {}", sessionId);
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment session does not exist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("WebSocket connectioned. after connection established open environment terminal begin... environment id: {}", envId);
|
||||||
|
EnvironmentEntity deviceEntity = environmentService.queryInfo(envId);
|
||||||
|
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
||||||
|
|
||||||
|
String urlStr = String.format("%s%s", paramJSONObject.getStr("url"), Constants.ENV_TERMINAL_WEBSOCKET_PATH);
|
||||||
|
urlStr = urlStr.replace("http", "ws");
|
||||||
|
WebSocket webSocket = null;
|
||||||
|
try {
|
||||||
|
HttpClient client = HttpClient.newHttpClient();
|
||||||
|
webSocket = client.newWebSocketBuilder()
|
||||||
|
.buildAsync(URI.create(urlStr), new WebSocketListener(session))
|
||||||
|
.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "Environment terminal webSocket connectioned. after connection established open environment terminal error. session id: {}", sessionId);
|
||||||
|
if (ObjectUtil.isNotNull(webSocket)) {
|
||||||
|
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotNull(session)) {
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment terminal webSocket connectioned. after connection established open environment terminal error!"));
|
||||||
|
IoUtil.close(session);
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("[afterConnectionEstablished] [environment terminal url: {}]", urlStr);
|
||||||
|
session.getAttributes().put("terminalWebsocket", webSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// WebSocket 监听器实现
|
||||||
|
private static class WebSocketListener implements WebSocket.Listener {
|
||||||
|
private WebSocketSession session;
|
||||||
|
|
||||||
|
public WebSocketListener(WebSocketSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onText(WebSocket webSocket, CharSequence message, boolean last) {
|
||||||
|
try {
|
||||||
|
// env -> asw
|
||||||
|
session.sendMessage(new TextMessage(message));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return WebSocket.Listener.super.onText(webSocket, message, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
|
||||||
|
log.info("Environment terminal webSocket connection closed, Status: " + statusCode + ", Reason: " + reason);
|
||||||
|
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||||
|
WebSocket terminalWebsocket = (WebSocket) session.getAttributes().get("terminalWebsocket");
|
||||||
|
try {
|
||||||
|
if (terminalWebsocket != null) {
|
||||||
|
terminalWebsocket.sendText(message.getPayload(), true);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||||
|
log.info("[afterConnectionClosed] [Terminal webSocket connection closed] [uri: {}]", session.getUri());
|
||||||
|
WebSocket envWebsocket = (WebSocket) session.getAttributes().get("terminalWebsocket");
|
||||||
|
if (envWebsocket != null) {
|
||||||
|
envWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
super.afterConnectionClosed(session, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package net.geedge.asw.common.config.websocket;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
|
import org.springframework.http.server.ServletServerHttpRequest;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.WebSocketHandler;
|
||||||
|
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EnvironmentWebSocketInterceptor extends HttpSessionHandshakeInterceptor {
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
private String regex = "^/api/v1/env/([^/]+)/session/([^/]+)/(novnc|terminal)$";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
||||||
|
if (request instanceof ServletServerHttpRequest) {
|
||||||
|
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||||
|
String servletPath = servletRequest.getServletRequest().getServletPath();
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(servletPath);
|
||||||
|
if (matcher.find()) {
|
||||||
|
attributes.put("envId", matcher.group(1));
|
||||||
|
attributes.put("sessionId", matcher.group(2));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String token = servletRequest.getServletRequest().getParameter("token");
|
||||||
|
StpUtil.setTokenValue(token);
|
||||||
|
String userId = StpUtil.getLoginIdAsString();
|
||||||
|
attributes.put("userId", userId);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("Websocket token authentication failed");
|
||||||
|
attributes.put("userId", T.StrUtil.EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.beforeHandshake(request, response, wsHandler, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
|
||||||
|
super.afterHandshake(request, response, wsHandler, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package net.geedge.asw.common.config.websocket;
|
||||||
|
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSocket
|
||||||
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService deviceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
|
registry.addHandler(new EnvironmentNovncWebSocketHandler(deviceService, environmentSessionService), "/api/v1/env/{envId}/session/{sessionId}/novnc")
|
||||||
|
.addInterceptors(new EnvironmentWebSocketInterceptor())
|
||||||
|
.setAllowedOrigins("*");
|
||||||
|
|
||||||
|
registry.addHandler(new EnvironmentTerminalWebSocketHandler(deviceService, environmentSessionService), "/api/v1/env/{envId}/session/{sessionId}/terminal")
|
||||||
|
.addInterceptors(new EnvironmentWebSocketInterceptor())
|
||||||
|
.setAllowedOrigins("*");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
package net.geedge.asw.common.util;
|
package net.geedge.asw.common.util;
|
||||||
|
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
@@ -15,6 +19,11 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp";
|
public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* playbook dir
|
||||||
|
*/
|
||||||
|
public static File PLAYBOOK_FILES_DIR = T.FileUtil.file(T.WebPathUtil.getRootPath(), "playbook_files");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 国际化语言列表
|
* 国际化语言列表
|
||||||
*/
|
*/
|
||||||
@@ -26,4 +35,84 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final List<String> VISIBILITY_LIST = T.ListUtil.of("public", "private");
|
public static final List<String> VISIBILITY_LIST = T.ListUtil.of("public", "private");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页码
|
||||||
|
*/
|
||||||
|
public static final String PAGE = "current";
|
||||||
|
/**
|
||||||
|
* 每页显示记录数
|
||||||
|
*/
|
||||||
|
public static final String LIMIT = "size";
|
||||||
|
/**
|
||||||
|
* 每页显示条数
|
||||||
|
*/
|
||||||
|
public static final long PAGESIZE = 20;
|
||||||
|
/**
|
||||||
|
* 排序方式
|
||||||
|
*/
|
||||||
|
public static final String ORDER = "orderBy";
|
||||||
|
/**
|
||||||
|
* 表名 和 排序字段对应关系 KEY: tablename
|
||||||
|
*/
|
||||||
|
public static final Map<String, Map<String, String>> TABLE_NAME_ORDER_FIELD_MAPPING = T.MapUtil.newHashMap();
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<String, String> applicationOrderFieldMap = new HashMap<>();
|
||||||
|
TABLE_NAME_ORDER_FIELD_MAPPING.put("application", applicationOrderFieldMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env api path prefix
|
||||||
|
*/
|
||||||
|
public static final String ENV_API_PREFIX = "/api/v1/env";
|
||||||
|
|
||||||
|
public static final String AUTH_TOKEN_CODE = "Authorization";
|
||||||
|
|
||||||
|
|
||||||
|
public static final Map<String, String> CORS_HEADER = T.MapUtil
|
||||||
|
.builder("Access-Control-Allow-Credentials", "true")
|
||||||
|
.put("Access-Control-Allow-Methods", "GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS")
|
||||||
|
.put("Access-Control-Max-Age", "18000").put("Access-Control-Allow-Origin", "*").build();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env api novnc websocket path
|
||||||
|
*/
|
||||||
|
public static final String ENV_NOVNC_WEBSOCKET_PATH = "/api/v1/env/novnc";
|
||||||
|
|
||||||
|
public static final String ENV_TERMINAL_WEBSOCKET_PATH = "/api/v1/env/terminal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env api stop tcpdump path
|
||||||
|
*/
|
||||||
|
public static final String ENV_API_TCPDUMP_PATH = "/api/v1/env/pcap";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env api status path
|
||||||
|
*/
|
||||||
|
public static final String ENV_API_STATUS_PATH = "/api/v1/env/status";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* novnc websocket 连接信息对应的 env session id 用以进行主动断开服务器连接功能
|
||||||
|
*/
|
||||||
|
public static final Map<String, WebSocketSession> ENV_NOVNC_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* terminal websocket 连接信息对应的 env session id 用以进行主动断开服务器连接功能
|
||||||
|
*/
|
||||||
|
public static final Map<String, WebSocketSession> ENV_TERMINAL_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android package type
|
||||||
|
*/
|
||||||
|
public static final List<String> ANDROID_PACKAGE_TYPE_LIST = T.ListUtil.of("xapk", "apk");
|
||||||
|
|
||||||
|
public static final String EMPTY_FILE_MD5 = "d41d8cd98f00b204e9800998ecf8427e";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tid -> jobId 用于获取 job 运行结果
|
||||||
|
*/
|
||||||
|
public static final Map<String, String> PLAYBOOK_EXECUTOR_RESULT = T.MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.geedge.asw.common.util;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
|
||||||
|
public class HttpContextUtils {
|
||||||
|
|
||||||
|
public static HttpServletRequest getHttpServletRequest() {
|
||||||
|
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/main/java/net/geedge/asw/common/util/IPUtils.java
Normal file
82
src/main/java/net/geedge/asw/common/util/IPUtils.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.geedge.asw.common.util;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP地址
|
||||||
|
*
|
||||||
|
* @author Mark sunlightcs@gmail.com
|
||||||
|
*/
|
||||||
|
public class IPUtils {
|
||||||
|
private static Log logger = Log.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取IP地址
|
||||||
|
*
|
||||||
|
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
|
||||||
|
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
|
||||||
|
*/
|
||||||
|
public static String getIpAddr(HttpServletRequest request) {
|
||||||
|
String ip = null;
|
||||||
|
try {
|
||||||
|
ip = request.getHeader("x-forwarded-for");
|
||||||
|
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("HTTP_CLIENT_IP");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("IPUtils ERROR ",e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// //使用代理,则获取第一个IP地址
|
||||||
|
// if(StringUtils.isEmpty(ip) && ip.length() > 15) {
|
||||||
|
// if(ip.indexOf(",") > 0) {
|
||||||
|
// ip = ip.substring(0, ip.indexOf(","));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 功能:判断一个IP是不是在一个网段下的
|
||||||
|
* 格式:isInRange("192.168.8.3", "192.168.9.10/22");
|
||||||
|
*/
|
||||||
|
public static boolean isInRange(String ip, String cidr) {
|
||||||
|
String[] ips = ip.split("\\.");
|
||||||
|
int ipAddr = (Integer.parseInt(ips[0]) << 24)
|
||||||
|
| (Integer.parseInt(ips[1]) << 16)
|
||||||
|
| (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
|
||||||
|
int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
|
||||||
|
int mask = 0xFFFFFFFF << (32 - type);
|
||||||
|
String cidrIp = cidr.replaceAll("/.*", "");
|
||||||
|
String[] cidrIps = cidrIp.split("\\.");
|
||||||
|
int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24)
|
||||||
|
| (Integer.parseInt(cidrIps[1]) << 16)
|
||||||
|
| (Integer.parseInt(cidrIps[2]) << 8)
|
||||||
|
| Integer.parseInt(cidrIps[3]);
|
||||||
|
|
||||||
|
return (ipAddr & mask) == (cidrIpAddr & mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,13 @@ public enum RCode {
|
|||||||
ROLE_ID_CANNOT_EMPTY(100010, "role id cannot be empty"),// 权限 ID 不能为空
|
ROLE_ID_CANNOT_EMPTY(100010, "role id cannot be empty"),// 权限 ID 不能为空
|
||||||
USER_NOT_EXIST(100011, "user does not exist"),
|
USER_NOT_EXIST(100011, "user does not exist"),
|
||||||
ROLE_NOT_EXIST(100012, "role does not exist"),
|
ROLE_NOT_EXIST(100012, "role does not exist"),
|
||||||
|
SYS_USER_NAME_CANNOT_EMPTY(100013, "username cannot be empty"),
|
||||||
|
SYS_ACCESS_LEVEL_CANNOT_EMPTY(100014, "accessLevel cannot be empty"),
|
||||||
|
SYS_WORKSPACE_ROLES_CANNOT_EMPTY(100015, "workspaceRoles cannot be empty"),
|
||||||
|
SYS_USER_BUILT_IN(100016, "Built-in user are not allowed to delete or update"),
|
||||||
|
SYS_ROLE_BUILT_IN(100017, "Built-in role are not allowed to delete or update"),
|
||||||
|
SYS_ROLE_NOT_DELETE(100018, "Used role cannot be deleted"),
|
||||||
|
SYS_USER_OLDPWD_INCORRECT(100019, "Incorrect old password. Please try again."),
|
||||||
|
|
||||||
|
|
||||||
// Application
|
// Application
|
||||||
@@ -34,11 +41,21 @@ public enum RCode {
|
|||||||
APP_DUPLICATE_RECORD(201007, "application duplicate record"),
|
APP_DUPLICATE_RECORD(201007, "application duplicate record"),
|
||||||
APP_NOT_EXIST(201008, "application does not exist"),
|
APP_NOT_EXIST(201008, "application does not exist"),
|
||||||
APP_PACKAGE_NAME_FORMAT_ERROR(201009, "application package name format error"),
|
APP_PACKAGE_NAME_FORMAT_ERROR(201009, "application package name format error"),
|
||||||
|
APP_TAGS_FORMAT_ERROR(201010, "application tags format error"),
|
||||||
|
APP_SIGNATURE_FORMAT_ERROR(201011, "application signature format error"),
|
||||||
|
APP_SIGNATURE_CONTENT_CANNOT_EMPTY(201012, "application signature content cannot be empty"),
|
||||||
|
APP_SIGNATURE_NOT_EXIST(201013, "application signature does not exist"),
|
||||||
|
APP_NOTE_CONTENT_CANNOT_EMPTY(201014, "application note content cannot be empty"),
|
||||||
|
APP_ATTACHMENT_NOT_EXIST(201015, "application attachment does not exist"),
|
||||||
|
APP_PROPERTIES_FORMAT_ERROR(201016, "application properties format error"),
|
||||||
|
APP_IMPORT_FILE_FORMAT_ERROR(201017, "application import file format error"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Package
|
// Package
|
||||||
PACKAGE_ID_CANNOT_EMPTY(202001, "package id cannot be empty"),
|
PACKAGE_ID_CANNOT_EMPTY(202001, "package id cannot be empty"),
|
||||||
PACKAGE_DESCRIPTION_CANNOT_EMPTY(202002, "package description cannot be empty"),
|
PACKAGE_DESCRIPTION_CANNOT_EMPTY(202002, "package description cannot be empty"),
|
||||||
|
PACKAGE_FILE_TYPE_ERROR(202003, "package invalid file"),
|
||||||
|
|
||||||
|
|
||||||
// Runner
|
// Runner
|
||||||
@@ -47,7 +64,7 @@ public enum RCode {
|
|||||||
|
|
||||||
// Playbook
|
// Playbook
|
||||||
PLAYBOOK_ID_CANNOT_EMPTY(302001, "playbook id cannot be empty"),
|
PLAYBOOK_ID_CANNOT_EMPTY(302001, "playbook id cannot be empty"),
|
||||||
|
PLAYBOOK_NAME_DUPLICATE(302002, "playbook name duplicate "),
|
||||||
|
|
||||||
// Workspace
|
// Workspace
|
||||||
WORKSPACE_ID_CANNOT_EMPTY(401001, "workspace id cannot be empty"),
|
WORKSPACE_ID_CANNOT_EMPTY(401001, "workspace id cannot be empty"),
|
||||||
@@ -59,11 +76,23 @@ public enum RCode {
|
|||||||
WORKSPACE_CANNOT_DELETE(401007, "Built-in workspace cannot be deleted"),
|
WORKSPACE_CANNOT_DELETE(401007, "Built-in workspace cannot be deleted"),
|
||||||
WORKSPACE_VISIBILITY_ERROR(401008, "workspace visibility error"),
|
WORKSPACE_VISIBILITY_ERROR(401008, "workspace visibility error"),
|
||||||
WORKSPACE_BUILT_IN(401009, "Built-in workspace cannot be update"),
|
WORKSPACE_BUILT_IN(401009, "Built-in workspace cannot be update"),
|
||||||
|
WORKSPACE_NOT_EXIST(401010, "Workspace does not exist"),
|
||||||
|
WORKSPACE_MEMBER_USER_ID_REPEAT(401011, "Workspace member user repeat"),
|
||||||
|
|
||||||
//PCAP
|
//PCAP
|
||||||
PCAP_UPLOAD_WEB_SHARK_ERROR(501001, "web shark upload pcap error"),
|
PCAP_UPLOAD_WEB_SHARK_ERROR(501001, "web shark upload pcap error"),
|
||||||
|
|
||||||
|
|
||||||
|
//environment
|
||||||
|
ENVIRONMENT_SESSION_NOT_EXIST(601001, "environment session does not exist"),
|
||||||
|
ENVIRONMENT_NOT_EXIST(601002, "environment does not exist"),
|
||||||
|
ENVIRONMENT_USED(601003, "The environment is already in use"),
|
||||||
|
ENVIRONMENT_STATUS_ERROR(601004, "The environment status is unavailable"),
|
||||||
|
ENVIRONMENT_ID_CANNOT_EMPTY(601005, "environment id cannot be empty"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SUCCESS(200, "success"); // 成功
|
SUCCESS(200, "success"); // 成功
|
||||||
|
|
||||||
private RCode(Integer code, String msg) {
|
private RCode(Integer code, String msg) {
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
package net.geedge.asw.common.util;
|
package net.geedge.asw.common.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
|
|
||||||
import com.j256.simplemagic.ContentInfo;
|
|
||||||
import com.j256.simplemagic.ContentInfoUtil;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.j256.simplemagic.ContentInfo;
|
||||||
|
import com.j256.simplemagic.ContentInfoUtil;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
public class ResponseUtil {
|
public class ResponseUtil {
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ public class ResponseUtil {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static void downloadFile(HttpServletResponse response, String contentType, String filename, byte[] data) throws IORuntimeException, IOException {
|
public static void downloadFile(HttpServletResponse response, String contentType, String filename, byte[] data) throws IORuntimeException, IOException {
|
||||||
String fileName = T.URLUtil.encode(filename, T.CharsetUtil.CHARSET_UTF_8);
|
String fileName = URLEncoder.encode(filename, "UTF-8");
|
||||||
ReflectUtil.invoke(response, "addHeader", "Content-Disposition", "attachment; filename=" + fileName);
|
ReflectUtil.invoke(response, "addHeader", "Content-Disposition", "attachment; filename=" + fileName);
|
||||||
ReflectUtil.invoke(response, "addHeader", "Content-Length", "" + data.length);
|
ReflectUtil.invoke(response, "addHeader", "Content-Length", "" + data.length);
|
||||||
ReflectUtil.invoke(response, "setHeader", "Access-Control-Expose-Headers", "Content-Disposition");
|
ReflectUtil.invoke(response, "setHeader", "Access-Control-Expose-Headers", "Content-Disposition");
|
||||||
@@ -46,7 +45,7 @@ public class ResponseUtil {
|
|||||||
public static void downloadFile(HttpServletResponse response, String filename, byte[] data)
|
public static void downloadFile(HttpServletResponse response, String filename, byte[] data)
|
||||||
throws IORuntimeException, IOException {
|
throws IORuntimeException, IOException {
|
||||||
response.setContentType(ResponseUtil.getDownloadContentType(filename));
|
response.setContentType(ResponseUtil.getDownloadContentType(filename));
|
||||||
String fileName = T.URLUtil.encode(filename, T.CharsetUtil.CHARSET_UTF_8);
|
String fileName = URLEncoder.encode(filename, "UTF-8");
|
||||||
// response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
|
// response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
|
||||||
// response.addHeader("Content-Length", "" + data.length);
|
// response.addHeader("Content-Length", "" + data.length);
|
||||||
// response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
// response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
||||||
|
|||||||
28
src/main/java/net/geedge/asw/common/util/TemplateUtil.java
Normal file
28
src/main/java/net/geedge/asw/common/util/TemplateUtil.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package net.geedge.asw.common.util;
|
||||||
|
|
||||||
|
import freemarker.cache.StringTemplateLoader;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.Template;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class TemplateUtil {
|
||||||
|
|
||||||
|
public static Template stringToTemplate(String templateStr,String templateKey) throws IOException {
|
||||||
|
|
||||||
|
// 创建配置类
|
||||||
|
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
|
||||||
|
//创建模板加载器
|
||||||
|
StringTemplateLoader templateLoader = new StringTemplateLoader();
|
||||||
|
// 存入模板
|
||||||
|
templateLoader.putTemplate(templateKey, templateStr); //template = 虚拟名称, 用来当作获取静态文件的key
|
||||||
|
//加载模板加载器
|
||||||
|
configuration.setTemplateLoader(templateLoader);
|
||||||
|
//得到模板
|
||||||
|
Template template = configuration.getTemplate(templateKey, "utf-8");
|
||||||
|
|
||||||
|
return template;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -387,6 +387,13 @@ public class VerifyUtil {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VerifyUtil json(RCode code) {
|
||||||
|
if (!T.JSONUtil.isTypeJSON(T.StrUtil.toStringOrNull(value))) {
|
||||||
|
throw ASWException.builder().rcode(code).build();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多参数校验,不能同时为空
|
* 多参数校验,不能同时为空
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,57 +1,60 @@
|
|||||||
package net.geedge.asw.module.app.controller;
|
package net.geedge.asw.module.app.controller;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
import net.geedge.asw.common.util.R;
|
import net.geedge.asw.common.util.R;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.*;
|
||||||
import net.geedge.asw.module.app.service.IApplicationService;
|
import net.geedge.asw.module.app.service.*;
|
||||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
import net.geedge.asw.module.sys.service.ISysUserService;
|
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/application")
|
@RequestMapping("/api/v1/application")
|
||||||
public class ApplicationController {
|
public class ApplicationController {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IApplicationService applicationService;
|
private IApplicationService applicationService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService userService;
|
private IApplicationSignatureService signatureService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationNoteService noteService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationHrefService hrefService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationAttachmentService attachmentService;
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public R detail(@PathVariable String id) {
|
public R detail(@PathVariable("id") String id, String workspaceId) {
|
||||||
ApplicationEntity entity = applicationService.getById(id);
|
T.VerifyUtil.is(workspaceId).notNull();
|
||||||
|
ApplicationEntity entity = applicationService.detail(id, workspaceId);
|
||||||
if (T.ObjectUtil.isNull(entity)) {
|
if (T.ObjectUtil.isNull(entity)) {
|
||||||
throw new ASWException(RCode.APP_NOT_EXIST);
|
throw new ASWException(RCode.APP_NOT_EXIST);
|
||||||
}
|
}
|
||||||
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
|
|
||||||
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
|
|
||||||
entity.setCreateUser(createUser);
|
|
||||||
entity.setUpdateUser(updateUser);
|
|
||||||
return R.ok().putData("record", entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}/{version}")
|
|
||||||
public R detail(@PathVariable String id,
|
|
||||||
@PathVariable(required = false) String version) {
|
|
||||||
ApplicationEntity entity = applicationService.getById(id);
|
|
||||||
if (T.StrUtil.isNotEmpty(version)){
|
|
||||||
entity = applicationService.queryByApplicationAndLog(id, version);
|
|
||||||
}
|
|
||||||
if (T.ObjectUtil.isNull(entity)){
|
|
||||||
throw new ASWException(RCode.APP_NOT_EXIST);
|
|
||||||
}
|
|
||||||
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
|
|
||||||
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
|
|
||||||
entity.setCreateUser(createUser);
|
|
||||||
entity.setUpdateUser(updateUser);
|
|
||||||
return R.ok().putData("record", entity);
|
return R.ok().putData("record", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,16 +68,53 @@ public class ApplicationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public R add(@RequestBody ApplicationEntity entity) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public R add(@RequestParam(required = true) String basic,
|
||||||
|
@RequestParam(required = false) String signature,
|
||||||
|
@RequestParam(required = false) String note,
|
||||||
|
@RequestParam(required = false) String hrefs,
|
||||||
|
@RequestParam(required = false, value = "files") List<MultipartFile> fileList) {
|
||||||
|
// validate
|
||||||
|
ApplicationEntity entity;
|
||||||
|
try {
|
||||||
|
entity = T.JSONUtil.toBean(basic, ApplicationEntity.class);
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(signature)) {
|
||||||
|
ApplicationSignatureEntity signatureEntity = T.JSONUtil.toBean(signature, ApplicationSignatureEntity.class);
|
||||||
|
entity.setSignature(signatureEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(note)) {
|
||||||
|
ApplicationNoteEntity noteEntity = T.JSONUtil.toBean(note, ApplicationNoteEntity.class);
|
||||||
|
entity.setNote(noteEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(hrefs)) {
|
||||||
|
T.JSONUtil.toList(hrefs, ApplicationHrefEntity.class);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[add] [param format error]");
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
T.VerifyUtil.is(entity).notNull()
|
T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getName()).notEmpty(RCode.APP_NAME_CANNOT_EMPTY)
|
.and(entity.getName()).notEmpty(RCode.APP_NAME_CANNOT_EMPTY)
|
||||||
//.and(entity.getLongName()).notEmpty(RCode.APP_LONGNAME_CANNOT_EMPTY)
|
|
||||||
//.and(entity.getProperties()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
|
|
||||||
//.and(entity.getSurrogates()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
|
||||||
//.and(entity.getDescription()).notEmpty(RCode.APP_DESCRIPTION_CANNOT_EMPTY)
|
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
// save application
|
||||||
ApplicationEntity applicationEntity = applicationService.saveApplication(entity);
|
ApplicationEntity applicationEntity = applicationService.saveApplication(entity);
|
||||||
|
|
||||||
|
// save attachment
|
||||||
|
fileList = T.CollUtil.defaultIfEmpty(fileList, new ArrayList<>());
|
||||||
|
for (MultipartFile file : fileList) {
|
||||||
|
attachmentService.saveAttachment(file.getResource(), applicationEntity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// save href
|
||||||
|
if (T.StrUtil.isNotEmpty(hrefs)) {
|
||||||
|
List<ApplicationHrefEntity> hrefList = T.JSONUtil.toList(hrefs, ApplicationHrefEntity.class);
|
||||||
|
hrefService.updateBatchHref(applicationEntity.getId(), hrefList);
|
||||||
|
}
|
||||||
return R.ok().putData("id", applicationEntity.getId());
|
return R.ok().putData("id", applicationEntity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,16 +123,44 @@ public class ApplicationController {
|
|||||||
T.VerifyUtil.is(entity).notNull()
|
T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||||
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
//.and(entity.getLongName()).notEmpty(RCode.APP_LONGNAME_CANNOT_EMPTY)
|
//.and(entity.getSignature()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
||||||
//.and(entity.getProperties()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
|
//.and(entity.getNote()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
|
||||||
//.and(entity.getSurrogates()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
|
||||||
//.and(entity.getDescription()).notEmpty(RCode.APP_DESCRIPTION_CANNOT_EMPTY)
|
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
|
||||||
ApplicationEntity applicationEntity = applicationService.updateApplication(entity);
|
ApplicationEntity applicationEntity = applicationService.updateApplication(entity);
|
||||||
return R.ok().putData("id", applicationEntity.getId());
|
return R.ok().putData("id", applicationEntity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PutMapping("/{id}/basic")
|
||||||
|
public R basic(@PathVariable String id, @RequestBody ApplicationEntity entity) {
|
||||||
|
T.VerifyUtil.is(entity).notNull()
|
||||||
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
|
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
entity.setId(id);
|
||||||
|
ApplicationEntity app = applicationService.updateBasic(entity);
|
||||||
|
return R.ok().putData("id", app.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{applicationId}/signature")
|
||||||
|
public R updateSignature(@PathVariable("applicationId") String applicationId, @RequestBody ApplicationSignatureEntity signature) {
|
||||||
|
T.VerifyUtil.is(signature).notNull()
|
||||||
|
.and(signature.getContent()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
||||||
|
.and(signature.getContent()).json(RCode.APP_SURROGATES_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
signatureService.saveSignature(signature, applicationId);
|
||||||
|
return R.ok().putData("id", signature.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{applicationId}/note")
|
||||||
|
public R updateNote(@PathVariable("applicationId") String applicationId, @RequestBody ApplicationNoteEntity note) {
|
||||||
|
T.VerifyUtil.is(note).notNull();
|
||||||
|
//.and(note.getContent()).notEmpty(RCode.APP_NOTE_CONTENT_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
noteService.saveNote(note, applicationId);
|
||||||
|
return R.ok().putData("id", note.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public R delete(String[] ids) {
|
public R delete(String[] ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
@@ -100,33 +168,156 @@ public class ApplicationController {
|
|||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}/log")
|
|
||||||
public R queryLogList(@PathVariable("id") String id) {
|
@GetMapping("/{applicationId}/attachment")
|
||||||
List<ApplicationEntity> applicationEntityList = applicationService.queryLogList(id);
|
public R queryAttachment(@PathVariable String applicationId) {
|
||||||
return R.ok().putData("record", applicationEntityList);
|
T.VerifyUtil.is(applicationId).notNull();
|
||||||
|
|
||||||
|
List<ApplicationAttachmentEntity> list = attachmentService.list(new LambdaQueryWrapper<ApplicationAttachmentEntity>().eq(ApplicationAttachmentEntity::getApplicationId, applicationId));
|
||||||
|
return R.ok().putData("records", list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/{id}/{oldVersion}/{newVersion}")
|
@GetMapping("/{applicationId}/attachment/{attachmentId}")
|
||||||
public R applicationCompare(@PathVariable("id") String id,
|
public void downloadAttachment(HttpServletResponse response, @PathVariable String applicationId, @PathVariable String attachmentId) throws IOException {
|
||||||
@PathVariable("oldVersion") String oldVersion,
|
T.VerifyUtil.is(applicationId).notNull()
|
||||||
@PathVariable("newVersion") String newVersion) {
|
.and(attachmentId).notNull();
|
||||||
List<ApplicationEntity> list = applicationService.compare(id, oldVersion, newVersion);
|
|
||||||
return R.ok().putData("record", list);
|
attachmentService.download(response, applicationId, attachmentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{applicationId}/attachment")
|
||||||
|
public R uploadAttachment(@PathVariable String applicationId, @RequestParam("files") List<MultipartFile> fileList) {
|
||||||
|
|
||||||
@PostMapping("/{id}/{version}/restore")
|
List<ApplicationAttachmentEntity> recordList = T.ListUtil.list(true);
|
||||||
public R restore(@PathVariable("id") String id,
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
@PathVariable("version") String version) {
|
MultipartFile file = fileList.get(i);
|
||||||
applicationService.restore(id, version);
|
ApplicationAttachmentEntity attachmentEntity = attachmentService.saveAttachment(file.getResource(), applicationId);
|
||||||
|
recordList.add(attachmentEntity);
|
||||||
|
}
|
||||||
|
return R.ok().putData("records", recordList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{applicationId}/attachment")
|
||||||
|
public R removedAttachment(@PathVariable String applicationId, @RequestParam String ids) {
|
||||||
|
|
||||||
|
attachmentService.removedAttachment(applicationId, ids);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/explore")
|
|
||||||
public R explore(@RequestParam String workspaceId, @RequestParam String pcapIds) {
|
@GetMapping("/{applicationId}/signature")
|
||||||
String discoverUrl = applicationService.generateKibanaDiscoverUrl(workspaceId, pcapIds);
|
public R querySignature(@PathVariable String applicationId) {
|
||||||
return R.ok().putData("url", discoverUrl);
|
T.VerifyUtil.is(applicationId).notNull();
|
||||||
|
List<ApplicationSignatureEntity> signatureList = signatureService.queryList(applicationId);
|
||||||
|
return R.ok().putData("records", signatureList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/{applicationId}/signature/{oldVersion}/{newVersion}")
|
||||||
|
public R signatureCompare(@PathVariable("applicationId") String applicationId,
|
||||||
|
@PathVariable("oldVersion") String oldVersion,
|
||||||
|
@PathVariable("newVersion") String newVersion) {
|
||||||
|
List<ApplicationSignatureEntity> list = signatureService.compare(applicationId, oldVersion, newVersion);
|
||||||
|
return R.ok().putData("records", list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PutMapping("/{applicationId}/signature/{version}/restore")
|
||||||
|
public R restore(@PathVariable("applicationId") String applicationId,
|
||||||
|
@PathVariable("version") String version) {
|
||||||
|
signatureService.restore(applicationId, version);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// application href
|
||||||
|
@GetMapping("/{applicationId}/href")
|
||||||
|
public R queryHref(@PathVariable String applicationId) {
|
||||||
|
List<ApplicationHrefEntity> entityList = hrefService.queryList(applicationId);
|
||||||
|
return R.ok().putData("records", entityList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/{applicationId}/href", method = {RequestMethod.POST, RequestMethod.PUT})
|
||||||
|
public R updateBatchHref(@PathVariable String applicationId, @RequestBody List<ApplicationHrefEntity> hrefList) {
|
||||||
|
// validate
|
||||||
|
ApplicationEntity application = applicationService.getById(applicationId);
|
||||||
|
T.VerifyUtil.is(application).notNull(RCode.APP_NOT_EXIST);
|
||||||
|
|
||||||
|
for (ApplicationHrefEntity href : hrefList) {
|
||||||
|
T.VerifyUtil.is(href).notNull()
|
||||||
|
.and(href.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
|
.and(href.getUrl()).notEmpty(RCode.PARAM_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
href.setApplicationId(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save or update batch
|
||||||
|
List<ApplicationHrefEntity> entityList = hrefService.updateBatchHref(hrefList);
|
||||||
|
List<Map<String, String>> records = entityList.stream()
|
||||||
|
.map(entity -> Map.of("id", entity.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return R.ok().putData("records", records);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{applicationId}/href")
|
||||||
|
public R deleteHref(@PathVariable String applicationId, @RequestParam String[] ids) {
|
||||||
|
// remove
|
||||||
|
hrefService.remove(new LambdaQueryWrapper<ApplicationHrefEntity>()
|
||||||
|
.eq(ApplicationHrefEntity::getApplicationId, applicationId)
|
||||||
|
.in(ApplicationHrefEntity::getId, T.ListUtil.of(ids)));
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/import")
|
||||||
|
public R importApplication(@RequestParam String workspaceId,
|
||||||
|
@RequestParam(defaultValue = "tsg2402") String format,
|
||||||
|
@RequestParam(value = "files") List<MultipartFile> fileList) {
|
||||||
|
// validate
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||||
|
T.VerifyUtil.is(workspace).notNull(RCode.WORKSPACE_NOT_EXIST);
|
||||||
|
|
||||||
|
List<JSONObject> dataList = T.ListUtil.list(true);
|
||||||
|
try {
|
||||||
|
for (MultipartFile multipartFile : fileList) {
|
||||||
|
String str = T.IoUtil.readUtf8(multipartFile.getInputStream());
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(str);
|
||||||
|
if (null == jsonObject.getJSONArray("applications")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dataList.add(jsonObject);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ASWException(RCode.APP_IMPORT_FILE_FORMAT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// import
|
||||||
|
List<ApplicationEntity> entityList = applicationService.importAppByFormat(workspaceId, format, dataList);
|
||||||
|
List<Map<String, String>> records = entityList.stream()
|
||||||
|
.map(entity -> Map.of("id", entity.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return R.ok().putData("records", records);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/export")
|
||||||
|
public void exportApplication(@RequestParam String workspaceId,
|
||||||
|
@RequestParam String ids,
|
||||||
|
@RequestParam(defaultValue = "tsg2402") String format,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
// validate
|
||||||
|
List<ApplicationEntity> appList = applicationService.list(
|
||||||
|
new LambdaQueryWrapper<ApplicationEntity>()
|
||||||
|
.eq(ApplicationEntity::getWorkspaceId, workspaceId)
|
||||||
|
.in(ApplicationEntity::getId, T.ListUtil.of(ids.split(",")))
|
||||||
|
);
|
||||||
|
T.VerifyUtil.is(appList).notEmpty(RCode.APP_NOT_EXIST);
|
||||||
|
|
||||||
|
// format
|
||||||
|
byte[] bytes = applicationService.exportAppByFormat(appList, format);
|
||||||
|
|
||||||
|
// response
|
||||||
|
T.ResponseUtil.downloadFile(response, T.StrUtil.concat(true, "application_", System.currentTimeMillis() + ".json"), bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package net.geedge.asw.module.app.controller;
|
||||||
|
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.R;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.service.IGitService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/workspace")
|
||||||
|
public class GitController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IGitService gitService;
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/branch")
|
||||||
|
public R listBranch(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam(value = "search", required = false) String search) {
|
||||||
|
List<Map<Object, Object>> list = gitService.listBranch(workspaceId, search);
|
||||||
|
return R.ok().putData("records", list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/branch/{branchName}")
|
||||||
|
public R infoBranch(@PathVariable("workspaceId") String workspaceId, @PathVariable("branchName") String branchName) {
|
||||||
|
Map<Object, Object> record = gitService.infoBranch(workspaceId, branchName);
|
||||||
|
return R.ok().putData("record", record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{workspaceId}/branch")
|
||||||
|
public R newBranch(@PathVariable("workspaceId") String workspaceId, @RequestBody Map<String, String> requestBody) {
|
||||||
|
String branch = T.MapUtil.getStr(requestBody, "branch", "");
|
||||||
|
String ref = T.MapUtil.getStr(requestBody, "ref", "");
|
||||||
|
if (T.StrUtil.hasEmpty(branch, ref)) {
|
||||||
|
throw new ASWException(RCode.PARAM_CANNOT_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Object, Object> record = gitService.newBranch(workspaceId, branch, ref);
|
||||||
|
return R.ok().putData("record", record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{workspaceId}/branch/{branchName}")
|
||||||
|
public R deleteBranch(@PathVariable("workspaceId") String workspaceId, @PathVariable("branchName") String branchName) {
|
||||||
|
gitService.deleteBranch(workspaceId, branchName);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,65 +1,71 @@
|
|||||||
package net.geedge.asw.module.app.controller;
|
package net.geedge.asw.module.app.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.common.util.R;
|
import net.geedge.asw.common.util.R;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.ResponseUtil;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
import net.geedge.asw.module.app.service.IPackageService;
|
import net.geedge.asw.module.app.service.IPackageService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/package")
|
@RequestMapping("/api/v1/workspace")
|
||||||
public class PackageController {
|
public class PackageController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPackageService packageService;
|
private IPackageService packageService;
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{workspaceId}/package/{id}")
|
||||||
public R detail(@PathVariable("id") String id) {
|
public R detail(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) {
|
||||||
PackageEntity entity = packageService.getById(id);
|
PackageEntity entity = packageService.queryInfo(id);
|
||||||
return R.ok().putData("record", entity);
|
return R.ok().putData("record", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping("/{workspaceId}/package")
|
||||||
public R list(@RequestParam Map<String, Object> params) {
|
public R list(@PathVariable("workspaceId") String workspaceId, @RequestParam Map<String, Object> params) {
|
||||||
T.VerifyUtil.is(params).notNull()
|
// workspaceId
|
||||||
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
params = T.MapUtil.defaultIfEmpty(params, new HashMap<>());
|
||||||
|
params.put("workspaceId", workspaceId);
|
||||||
|
|
||||||
Page page = packageService.queryList(params);
|
Page page = packageService.queryList(params);
|
||||||
return R.ok(page);
|
return R.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping("/{workspaceId}/package")
|
||||||
public R add(@RequestBody PackageEntity entity) {
|
public R add(@PathVariable(value = "workspaceId", required = true) String workspaceId,
|
||||||
T.VerifyUtil.is(entity).notNull()
|
@RequestParam(value = "description", required = false) String description,
|
||||||
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
@RequestParam(value = "file") MultipartFile file) {
|
||||||
.and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY)
|
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
|
||||||
|
|
||||||
PackageEntity pkgEntity = packageService.savePackage(entity);
|
PackageEntity entity = packageService.savePackage(workspaceId, description, file.getResource());
|
||||||
return R.ok().putData("id", pkgEntity.getId());
|
return R.ok().putData("record", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping
|
@DeleteMapping("/{workspaceId}/package")
|
||||||
public R update(@RequestBody PackageEntity entity) {
|
|
||||||
T.VerifyUtil.is(entity).notNull()
|
|
||||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
|
||||||
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
|
||||||
.and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY)
|
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
|
||||||
|
|
||||||
PackageEntity pkgEntity = packageService.updatePackage(entity);
|
|
||||||
return R.ok().putData("id", pkgEntity.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping
|
|
||||||
public R delete(String[] ids) {
|
public R delete(String[] ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
packageService.removePackage(T.ListUtil.of(ids));
|
packageService.removePackage(T.ListUtil.of(ids));
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/package/{id}/download")
|
||||||
|
public void download(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@PathVariable("id") String id,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
PackageEntity entity = packageService.getById(id);
|
||||||
|
T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
File pkgFile = T.FileUtil.file(entity.getPath());
|
||||||
|
ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, entity.getName(), T.FileUtil.readBytes(pkgFile));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.geedge.asw.module.app.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ApplicationAttachmentDao extends BaseMapper<ApplicationAttachmentEntity>{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,8 +4,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import org.apache.ibatis.annotations.Select;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -14,13 +12,4 @@ import java.util.Map;
|
|||||||
public interface ApplicationDao extends BaseMapper<ApplicationEntity>{
|
public interface ApplicationDao extends BaseMapper<ApplicationEntity>{
|
||||||
|
|
||||||
List<ApplicationEntity> queryList(Page page, Map<String, Object> params);
|
List<ApplicationEntity> queryList(Page page, Map<String, Object> params);
|
||||||
|
|
||||||
@Select("select * from ( select * from application union select * from application_log ) app where app.id = #{id} and app.op_version = #{version}")
|
|
||||||
ApplicationEntity queryByApplicationAndLog(String id, String version);
|
|
||||||
|
|
||||||
List<ApplicationEntity> queryLogList(String id);
|
|
||||||
|
|
||||||
List<ApplicationEntity> compare(@Param("params") Map<String, Object> params);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.geedge.asw.module.app.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationHrefEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ApplicationHrefDao extends BaseMapper<ApplicationHrefEntity> {
|
||||||
|
|
||||||
|
List<ApplicationHrefEntity> queryList(@Param("applicationId") String applicationId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package net.geedge.asw.module.app.dao;
|
package net.geedge.asw.module.app.dao;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import net.geedge.asw.module.app.entity.SignatureEntity;
|
import net.geedge.asw.module.app.entity.ApplicationNoteEntity;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface SignatureDao extends BaseMapper<SignatureEntity>{
|
public interface ApplicationNoteDao extends BaseMapper<ApplicationNoteEntity>{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.geedge.asw.module.app.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationSignatureEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ApplicationSignatureDao extends BaseMapper<ApplicationSignatureEntity>{
|
||||||
|
|
||||||
|
List<ApplicationSignatureEntity> queryList(@Param("params") Map<Object, Object> params);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.geedge.asw.module.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("application_attachment")
|
||||||
|
public class ApplicationAttachmentEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String applicationId;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
private Long createTimestamp;
|
||||||
|
|
||||||
|
private String createUserId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,30 +4,46 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("application")
|
@TableName(value = "application", autoResultMap = true)
|
||||||
public class ApplicationEntity {
|
public class ApplicationEntity {
|
||||||
|
|
||||||
@TableId(type = IdType.ASSIGN_UUID)
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String longName;
|
|
||||||
private String properties;
|
private String tags;
|
||||||
private String description;
|
|
||||||
private String surrogates;
|
|
||||||
private String packageName;
|
private String packageName;
|
||||||
|
|
||||||
private String website;
|
private String website;
|
||||||
|
|
||||||
private String provider;
|
private String provider;
|
||||||
|
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
private Object properties;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
|
|
||||||
private Long updateTimestamp;
|
private Long updateTimestamp;
|
||||||
|
|
||||||
private String createUserId;
|
private String createUserId;
|
||||||
|
|
||||||
private String updateUserId;
|
private String updateUserId;
|
||||||
|
|
||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
|
||||||
private Integer opVersion;
|
private Integer opVersion;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
@@ -36,4 +52,16 @@ public class ApplicationEntity {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private SysUserEntity updateUser;
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private ApplicationSignatureEntity signature;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private ApplicationNoteEntity note;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<ApplicationAttachmentEntity> attatchments;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<ApplicationHrefEntity> hrefs;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.geedge.asw.module.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName(value = "application_href", autoResultMap = true)
|
||||||
|
public class ApplicationHrefEntity implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
private String applicationId;
|
||||||
|
private String name;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||||
|
private Long createTimestamp;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||||
|
private String createUserId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,27 +1,61 @@
|
|||||||
package net.geedge.asw.module.app.entity;
|
package net.geedge.asw.module.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("application_log")
|
@TableName(value = "application_log", autoResultMap = true)
|
||||||
public class ApplicationLogEntity {
|
public class ApplicationLogEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String longName;
|
|
||||||
private String properties;
|
private String tags;
|
||||||
private String description;
|
|
||||||
private String surrogates;
|
|
||||||
private String packageName;
|
private String packageName;
|
||||||
|
|
||||||
private String website;
|
private String website;
|
||||||
|
|
||||||
private String provider;
|
private String provider;
|
||||||
|
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
private String properties;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
|
|
||||||
private Long updateTimestamp;
|
private Long updateTimestamp;
|
||||||
|
|
||||||
private String createUserId;
|
private String createUserId;
|
||||||
|
|
||||||
private String updateUserId;
|
private String updateUserId;
|
||||||
|
|
||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
|
||||||
private Integer opVersion;
|
private Integer opVersion;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private ApplicationSignatureEntity signature;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private ApplicationNoteEntity note;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<ApplicationAttachmentEntity> attatchments;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,20 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("signature")
|
@TableName("application_note")
|
||||||
public class SignatureEntity {
|
public class ApplicationNoteEntity {
|
||||||
|
|
||||||
@TableId(type = IdType.ASSIGN_UUID)
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
private String appId;
|
|
||||||
private String name;
|
private String applicationId;
|
||||||
private String tags;
|
|
||||||
private String description;
|
private String content;
|
||||||
private Integer displayFlag;
|
|
||||||
private String conditions;
|
|
||||||
private Long opVersion;
|
|
||||||
|
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
private Long updateTimestamp;
|
|
||||||
private String createUserId;
|
|
||||||
private String updateUserId;
|
|
||||||
|
|
||||||
private String workspaceId;
|
private String createUserId;
|
||||||
|
|
||||||
|
private Long opVersion;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.geedge.asw.module.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("application_signature")
|
||||||
|
public class ApplicationSignatureEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String applicationId;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private Long createTimestamp;
|
||||||
|
|
||||||
|
private String createUserId;
|
||||||
|
|
||||||
|
private Long opVersion;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("package")
|
@TableName("package")
|
||||||
@@ -13,11 +14,13 @@ public class PackageEntity {
|
|||||||
@TableId(type = IdType.ASSIGN_UUID)
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private String logo;
|
private String icon;
|
||||||
private String description;
|
private String description;
|
||||||
private String platform;
|
private String platform;
|
||||||
private String version;
|
private String version;
|
||||||
private String identifier;
|
private String identifier;
|
||||||
|
private String path;
|
||||||
|
private Long size;
|
||||||
|
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
private Long updateTimestamp;
|
private Long updateTimestamp;
|
||||||
@@ -27,6 +30,9 @@ public class PackageEntity {
|
|||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String workbookId;
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface IApplicationAttachmentService extends IService<ApplicationAttachmentEntity>{
|
||||||
|
|
||||||
|
ApplicationAttachmentEntity saveAttachment(Resource fileResource, String applicationId);
|
||||||
|
|
||||||
|
void removedAttachment(String applicationId, String ids);
|
||||||
|
|
||||||
|
void download(HttpServletResponse response, String applicationId, String attachmentId) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationHrefEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IApplicationHrefService extends IService<ApplicationHrefEntity> {
|
||||||
|
|
||||||
|
List<ApplicationHrefEntity> queryList(String applicationId);
|
||||||
|
|
||||||
|
List<ApplicationHrefEntity> updateBatchHref(List<ApplicationHrefEntity> hrefList);
|
||||||
|
|
||||||
|
List<ApplicationHrefEntity> updateBatchHref(String applicationId, List<ApplicationHrefEntity> hrefList);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationNoteEntity;
|
||||||
|
|
||||||
|
public interface IApplicationNoteService extends IService<ApplicationNoteEntity>{
|
||||||
|
|
||||||
|
void saveNote(ApplicationNoteEntity note, String applicationId);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.geedge.asw.module.app.service;
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
@@ -9,22 +10,20 @@ import java.util.Map;
|
|||||||
|
|
||||||
public interface IApplicationService extends IService<ApplicationEntity>{
|
public interface IApplicationService extends IService<ApplicationEntity>{
|
||||||
|
|
||||||
|
ApplicationEntity detail(String id, String workspaceId);
|
||||||
|
|
||||||
Page queryList(Map<String, Object> params);
|
Page queryList(Map<String, Object> params);
|
||||||
|
|
||||||
ApplicationEntity saveApplication(ApplicationEntity entity);
|
ApplicationEntity saveApplication(ApplicationEntity entity);
|
||||||
|
|
||||||
ApplicationEntity updateApplication(ApplicationEntity entity);
|
ApplicationEntity updateApplication(ApplicationEntity entity);
|
||||||
|
|
||||||
|
ApplicationEntity updateBasic(ApplicationEntity entity);
|
||||||
|
|
||||||
void removeApplication(List<String> ids);
|
void removeApplication(List<String> ids);
|
||||||
|
|
||||||
ApplicationEntity queryByApplicationAndLog(String id, String version);
|
byte[] exportAppByFormat(List<ApplicationEntity> appList, String format);
|
||||||
|
|
||||||
List<ApplicationEntity> compare(String id, String oldVersion, String newVersion);
|
List<ApplicationEntity> importAppByFormat(String workspaceId, String format, List<JSONObject> dataList);
|
||||||
|
|
||||||
List<ApplicationEntity> queryLogList(String id);
|
|
||||||
|
|
||||||
void restore(String id, String version);
|
|
||||||
|
|
||||||
String generateKibanaDiscoverUrl(String workspaceId, String pcapIds);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationSignatureEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IApplicationSignatureService extends IService<ApplicationSignatureEntity>{
|
||||||
|
|
||||||
|
void saveSignature(ApplicationSignatureEntity signature, String applicationId);
|
||||||
|
|
||||||
|
List<ApplicationSignatureEntity> queryList(String applicationId);
|
||||||
|
|
||||||
|
List<ApplicationSignatureEntity> compare(String applicationId, String oldVersion, String newVersion);
|
||||||
|
|
||||||
|
void restore(String id, String version);
|
||||||
|
|
||||||
|
ApplicationSignatureEntity queryLastVersionSignatureByAppId(String applicationId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface IGitService {
|
||||||
|
|
||||||
|
List<Map<Object, Object>> listBranch(String workspaceId, String search);
|
||||||
|
|
||||||
|
Map<Object, Object> infoBranch(String workspaceId, String branchName);
|
||||||
|
|
||||||
|
Map<Object, Object> newBranch(String workspaceId, String branchName, String ref);
|
||||||
|
|
||||||
|
void deleteBranch(String workspaceId, String branchName);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,17 +3,18 @@ package net.geedge.asw.module.app.service;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public interface IPackageService extends IService<PackageEntity>{
|
public interface IPackageService extends IService<PackageEntity>{
|
||||||
|
|
||||||
|
PackageEntity queryInfo(String id);
|
||||||
|
|
||||||
Page queryList(Map<String, Object> params);
|
Page queryList(Map<String, Object> params);
|
||||||
|
|
||||||
PackageEntity savePackage(PackageEntity entity);
|
PackageEntity savePackage(String workspaceId, String description, Resource fileResource);
|
||||||
|
|
||||||
PackageEntity updatePackage(PackageEntity entity);
|
|
||||||
|
|
||||||
void removePackage(List<String> ids);
|
void removePackage(List<String> ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package net.geedge.asw.module.app.service;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
|
||||||
import net.geedge.asw.module.app.entity.SignatureEntity;
|
|
||||||
|
|
||||||
public interface ISignatureService extends IService<SignatureEntity>{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.geedge.asw.module.app.service;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ITSGApplicationService {
|
||||||
|
|
||||||
|
Map<Object, Object> aswToTsg2402(List<ApplicationEntity> appList);
|
||||||
|
|
||||||
|
List<ApplicationEntity> tsg2402ToAsw(String workspaceId, List<JSONObject> dataList);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.dao.ApplicationAttachmentDao;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationAttachmentService;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationService;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.MediaTypeFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApplicationAttachmentServiceImpl extends ServiceImpl<ApplicationAttachmentDao, ApplicationAttachmentEntity> implements IApplicationAttachmentService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationService applicationService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApplicationAttachmentEntity saveAttachment(Resource fileResource, String applicationId) {
|
||||||
|
|
||||||
|
ApplicationEntity app = applicationService.getById(applicationId);
|
||||||
|
ApplicationAttachmentEntity entity = new ApplicationAttachmentEntity();
|
||||||
|
try {
|
||||||
|
entity.setName(fileResource.getFilename());
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setApplicationId(applicationId);
|
||||||
|
|
||||||
|
// path
|
||||||
|
File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), app.getId(), fileResource.getFilename());
|
||||||
|
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
|
||||||
|
entity.setPath(destination.getPath());
|
||||||
|
|
||||||
|
// 根据文件 applicationId path 判断是否已上存在,存在则响应当前实体
|
||||||
|
ApplicationAttachmentEntity attachment = this.getOne(new LambdaQueryWrapper<ApplicationAttachmentEntity>()
|
||||||
|
.eq(ApplicationAttachmentEntity::getApplicationId, applicationId)
|
||||||
|
.eq(ApplicationAttachmentEntity::getPath, destination.getPath()));
|
||||||
|
if (T.ObjectUtil.isNotNull(attachment)) {
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save
|
||||||
|
this.save(entity);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e, "[saveAttachment] [error] [applicationId: {}]", applicationId);
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedAttachment(String applicationId, String ids) {
|
||||||
|
|
||||||
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
|
|
||||||
|
for (String id : idList) {
|
||||||
|
ApplicationAttachmentEntity attachment = this.getOne(new LambdaQueryWrapper<ApplicationAttachmentEntity>()
|
||||||
|
.eq(ApplicationAttachmentEntity::getApplicationId, applicationId)
|
||||||
|
.eq(ApplicationAttachmentEntity::getId, id));
|
||||||
|
|
||||||
|
T.FileUtil.del(FileUtil.file(attachment.getPath()));
|
||||||
|
this.removeById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void download(HttpServletResponse response, String applicationId, String attachmentId) throws IOException {
|
||||||
|
ApplicationAttachmentEntity attachment = this.getOne(new LambdaQueryWrapper<ApplicationAttachmentEntity>()
|
||||||
|
.eq(ApplicationAttachmentEntity::getApplicationId, applicationId)
|
||||||
|
.eq(ApplicationAttachmentEntity::getId, attachmentId));
|
||||||
|
if (T.ObjectUtil.isNull(attachment)) {
|
||||||
|
throw new ASWException(RCode.APP_ATTACHMENT_NOT_EXIST);
|
||||||
|
}
|
||||||
|
File file = FileUtil.file(attachment.getPath());
|
||||||
|
response.setStatus(200);
|
||||||
|
response.setContentType( MediaTypeFactory.getMediaType(file.getName()).toString());
|
||||||
|
response.setContentLength(Integer.parseInt(String.valueOf(file.length())));
|
||||||
|
response.setHeader("Content-disposition", "attachment; filename=" + file.getName());
|
||||||
|
response.getOutputStream().write(T.FileUtil.readBytes(file));
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.dao.ApplicationHrefDao;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationHrefEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationHrefService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApplicationHrefServiceImpl extends ServiceImpl<ApplicationHrefDao, ApplicationHrefEntity> implements IApplicationHrefService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApplicationHrefEntity> queryList(String applicationId) {
|
||||||
|
return this.getBaseMapper().queryList(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public List<ApplicationHrefEntity> updateBatchHref(List<ApplicationHrefEntity> hrefList) {
|
||||||
|
for (ApplicationHrefEntity entity : hrefList) {
|
||||||
|
|
||||||
|
// validate
|
||||||
|
ApplicationHrefEntity one = this.getOne(new LambdaQueryWrapper<ApplicationHrefEntity>()
|
||||||
|
.eq(ApplicationHrefEntity::getApplicationId, entity.getApplicationId())
|
||||||
|
.eq(ApplicationHrefEntity::getName, entity.getName())
|
||||||
|
.ne(T.ObjectUtil.isNotEmpty(entity.getId()), ApplicationHrefEntity::getId, entity.getId()));
|
||||||
|
if (T.ObjectUtil.isNotNull(one)) {
|
||||||
|
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
|
// save or update
|
||||||
|
this.saveOrUpdate(entity);
|
||||||
|
}
|
||||||
|
return hrefList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApplicationHrefEntity> updateBatchHref(String applicationId, List<ApplicationHrefEntity> hrefList) {
|
||||||
|
for (ApplicationHrefEntity entity : hrefList) {
|
||||||
|
entity.setApplicationId(applicationId);
|
||||||
|
}
|
||||||
|
return this.updateBatchHref(hrefList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.dao.ApplicationNoteDao;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationNoteEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationNoteService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApplicationNoteServiceImpl extends ServiceImpl<ApplicationNoteDao, ApplicationNoteEntity> implements IApplicationNoteService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveNote(ApplicationNoteEntity note, String applicationId) {
|
||||||
|
// query last note
|
||||||
|
ApplicationNoteEntity noteLast = this.getOne(new LambdaQueryWrapper<ApplicationNoteEntity>()
|
||||||
|
.eq(ApplicationNoteEntity::getApplicationId, applicationId)
|
||||||
|
.orderByDesc(ApplicationNoteEntity::getOpVersion)
|
||||||
|
.last("limit 1"));
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(noteLast)){
|
||||||
|
note.setOpVersion(noteLast.getOpVersion() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save note
|
||||||
|
note.setApplicationId(applicationId);
|
||||||
|
note.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
note.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
|
this.save(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +1,89 @@
|
|||||||
package net.geedge.asw.module.app.service.impl;
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.net.url.UrlBuilder;
|
import cn.hutool.json.JSON;
|
||||||
|
import cn.hutool.json.JSONConfig;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.dao.ApplicationDao;
|
import net.geedge.asw.module.app.dao.ApplicationDao;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.*;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
import net.geedge.asw.module.app.service.*;
|
||||||
import net.geedge.asw.module.app.service.IApplicationLogService;
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
import net.geedge.asw.module.app.service.IApplicationService;
|
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||||
import net.geedge.asw.module.feign.client.KibanaClient;
|
|
||||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
|
||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
|
||||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
|
||||||
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
|
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
|
||||||
|
|
||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
@Value("${kibana.url:127.0.0.1:5601}")
|
|
||||||
private String kibanaUrl;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IApplicationLogService applicationLogService;
|
private IApplicationLogService applicationLogService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IWorkspaceService workspaceService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPcapService pcapService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
@Resource
|
@Autowired
|
||||||
private KibanaClient kibanaClient;
|
private IApplicationSignatureService signatureService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationNoteService noteService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationHrefService hrefService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationAttachmentService attachmentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITSGApplicationService tsgApplicationService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApplicationEntity queryByApplicationAndLog(String id, String version) {
|
public ApplicationEntity detail(String id, String workspaceId) {
|
||||||
ApplicationEntity entity = this.baseMapper.queryByApplicationAndLog(id, version);
|
ApplicationEntity app = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
||||||
return entity;
|
.eq(ApplicationEntity::getId, id)
|
||||||
|
.eq(ApplicationEntity::getWorkspaceId, workspaceId));
|
||||||
|
|
||||||
|
ApplicationSignatureEntity signature = signatureService.getOne(new LambdaQueryWrapper<ApplicationSignatureEntity>()
|
||||||
|
.eq(ApplicationSignatureEntity::getApplicationId, app.getId())
|
||||||
|
.orderByDesc(ApplicationSignatureEntity::getOpVersion)
|
||||||
|
.last("limit 1"));
|
||||||
|
app.setSignature(signature);
|
||||||
|
|
||||||
|
ApplicationNoteEntity note = noteService.getOne(new LambdaQueryWrapper<ApplicationNoteEntity>()
|
||||||
|
.eq(ApplicationNoteEntity::getApplicationId, app.getId())
|
||||||
|
.orderByDesc(ApplicationNoteEntity::getOpVersion)
|
||||||
|
.last("limit 1"));
|
||||||
|
app.setNote(note);
|
||||||
|
|
||||||
|
List<ApplicationAttachmentEntity> attachmentEntityList = attachmentService.list(new LambdaQueryWrapper<ApplicationAttachmentEntity>()
|
||||||
|
.eq(ApplicationAttachmentEntity::getApplicationId, app.getId()));
|
||||||
|
attachmentEntityList.stream().forEach(x -> x.setPath(null));
|
||||||
|
app.setAttatchments(attachmentEntityList);
|
||||||
|
|
||||||
|
List<ApplicationHrefEntity> hrefEntityList = hrefService.list(new LambdaQueryWrapper<ApplicationHrefEntity>()
|
||||||
|
.eq(ApplicationHrefEntity::getApplicationId, app.getId()));
|
||||||
|
app.setHrefs(hrefEntityList);
|
||||||
|
|
||||||
|
SysUserEntity createUser = userService.getById(app.getCreateUserId());
|
||||||
|
SysUserEntity updateUser = userService.getById(app.getUpdateUserId());
|
||||||
|
app.setCreateUser(createUser);
|
||||||
|
app.setUpdateUser(updateUser);
|
||||||
|
|
||||||
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -67,44 +94,84 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, Applicat
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void validateParam(ApplicationEntity entity, boolean isUpdate) {
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public ApplicationEntity saveApplication(ApplicationEntity entity) {
|
|
||||||
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
||||||
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
|
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
|
||||||
.eq(ApplicationEntity::getName, entity.getName()));
|
.eq(ApplicationEntity::getName, entity.getName()));
|
||||||
if (T.ObjectUtil.isNotNull(one)) {
|
|
||||||
|
if (T.ObjectUtil.isNotNull(one) && !isUpdate || T.ObjectUtil.isNotNull(one) && isUpdate && !T.StrUtil.equals(entity.getId(), one.getId())) {
|
||||||
throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build();
|
throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// package name format
|
||||||
if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())) {
|
if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())) {
|
||||||
throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build();
|
throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build();
|
||||||
} else if (T.ObjectUtil.isEmpty(entity.getPackageName())) {
|
} else if (T.ObjectUtil.isEmpty(entity.getPackageName())) {
|
||||||
entity.setPackageName("{}");
|
entity.setPackageName("{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tags name format
|
||||||
|
if (T.StrUtil.isNotEmpty(entity.getTags()) && !T.JSONUtil.isTypeJSON(entity.getTags())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_TAGS_FORMAT_ERROR).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// signature
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getSignature())) {
|
||||||
|
if (!T.StrUtil.isNotEmpty(entity.getSignature().getContent())){
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_SIGNATURE_CONTENT_CANNOT_EMPTY).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!T.JSONUtil.isTypeJSON(entity.getSignature().getContent())){
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_SIGNATURE_CONTENT_CANNOT_EMPTY).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note
|
||||||
|
/* if (T.ObjectUtil.isNotEmpty(entity.getNote()) && !T.StrUtil.isNotEmpty(entity.getNote().getContent())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_NOTE_CONTENT_CANNOT_EMPTY).build();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// properties
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getProperties()) && !T.JSONUtil.isTypeJSON(entity.getProperties().toString())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_PROPERTIES_FORMAT_ERROR).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ApplicationEntity saveApplication(ApplicationEntity entity) {
|
||||||
|
|
||||||
|
this.validateParam(entity, false);
|
||||||
|
|
||||||
|
// save
|
||||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
// save
|
|
||||||
this.save(entity);
|
this.save(entity);
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getSignature())){
|
||||||
|
// save signature
|
||||||
|
signatureService.saveSignature(entity.getSignature(), entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getNote())){
|
||||||
|
//save note
|
||||||
|
noteService.saveNote(entity.getNote(), entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public ApplicationEntity updateApplication(ApplicationEntity entity) {
|
public ApplicationEntity updateApplication(ApplicationEntity entity) {
|
||||||
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
|
||||||
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
|
this.validateParam(entity, true);
|
||||||
.eq(ApplicationEntity::getId, entity.getId()));
|
|
||||||
if (T.ObjectUtil.isNull(one)) {
|
ApplicationEntity one = this.getById(entity.getId());
|
||||||
throw ASWException.builder().rcode(RCode.APP_NOT_EXIST).build();
|
|
||||||
}
|
|
||||||
if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())){
|
|
||||||
throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build();
|
|
||||||
}else if (T.ObjectUtil.isEmpty(entity.getPackageName())){
|
|
||||||
entity.setPackageName("{}");
|
|
||||||
}
|
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
entity.setOpVersion(one.getOpVersion() + 1);
|
entity.setOpVersion(one.getOpVersion() + 1);
|
||||||
@@ -113,11 +180,22 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, Applicat
|
|||||||
this.updateById(entity);
|
this.updateById(entity);
|
||||||
|
|
||||||
// save log
|
// save log
|
||||||
this.saveApplcationToLog(one);
|
this.saveApplicationToLog(one);
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getSignature())){
|
||||||
|
// save signature
|
||||||
|
signatureService.saveSignature(entity.getSignature(), entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getNote())){
|
||||||
|
//save note
|
||||||
|
noteService.saveNote(entity.getNote(), entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveApplcationToLog(ApplicationEntity one) {
|
private void saveApplicationToLog(ApplicationEntity one) {
|
||||||
ApplicationLogEntity applicationLogEntity = T.BeanUtil.toBean(one, ApplicationLogEntity.class);
|
ApplicationLogEntity applicationLogEntity = T.BeanUtil.toBean(one, ApplicationLogEntity.class);
|
||||||
applicationLogEntity.setUpdateTimestamp(System.currentTimeMillis());
|
applicationLogEntity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
applicationLogEntity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
applicationLogEntity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
@@ -132,122 +210,77 @@ public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, Applicat
|
|||||||
// remove
|
// remove
|
||||||
this.removeBatchByIds(ids);
|
this.removeBatchByIds(ids);
|
||||||
applicationLogService.removeBatchByIds(ids);
|
applicationLogService.removeBatchByIds(ids);
|
||||||
|
signatureService.remove(new LambdaQueryWrapper<ApplicationSignatureEntity>().in(ApplicationSignatureEntity::getApplicationId, ids));
|
||||||
|
noteService.remove(new LambdaQueryWrapper<ApplicationNoteEntity>().in(ApplicationNoteEntity::getApplicationId, ids));
|
||||||
|
attachmentService.remove(new LambdaQueryWrapper<ApplicationAttachmentEntity>().in(ApplicationAttachmentEntity::getApplicationId, ids));
|
||||||
|
hrefService.remove(new LambdaQueryWrapper<ApplicationHrefEntity>().in(ApplicationHrefEntity::getApplicationId, ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ApplicationEntity> queryLogList(String id) {
|
public ApplicationEntity updateBasic(ApplicationEntity entity) {
|
||||||
List<ApplicationEntity> packageList = this.getBaseMapper().queryLogList(id);
|
|
||||||
return packageList;
|
ApplicationEntity one = this.getById(entity.getId());
|
||||||
|
if (T.ObjectUtil.isNotNull(one) && !T.StrUtil.equals(entity.getId(), one.getId())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// package name format
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build();
|
||||||
|
} else if (T.ObjectUtil.isEmpty(entity.getPackageName())) {
|
||||||
|
entity.setPackageName("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// properties
|
||||||
|
if (T.ObjectUtil.isNotEmpty(entity.getProperties()) && !T.JSONUtil.isTypeJSON(entity.getProperties().toString())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_PROPERTIES_FORMAT_ERROR).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setOpVersion(one.getOpVersion() + 1);
|
||||||
|
|
||||||
|
this.saveApplicationToLog(one);
|
||||||
|
this.updateById(entity);
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ApplicationEntity> compare(String id, String oldVersion, String newVersion) {
|
public byte[] exportAppByFormat(List<ApplicationEntity> appList, String format) {
|
||||||
Map<String, Object> params = Map.of("id", id, "versions", Arrays.asList(oldVersion, newVersion));
|
try {
|
||||||
List<ApplicationEntity> packageList = this.getBaseMapper().compare(params);
|
switch (format) {
|
||||||
return packageList;
|
case "tsg2402": {
|
||||||
|
Map<Object, Object> m = tsgApplicationService.aswToTsg2402(appList);
|
||||||
|
JSON json = new JSONObject(m, JSONConfig.create().setIgnoreNullValue(false).setKeyComparator(String::compareToIgnoreCase));
|
||||||
|
return T.StrUtil.bytes(json.toJSONString(0));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new byte[]{};
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[exportAppByFormat] [error] [format: {}] [application: {}]", format, T.JSONUtil.toJsonStr(appList));
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void restore(String id, String version) {
|
public List<ApplicationEntity> importAppByFormat(String workspaceId, String format, List<JSONObject> dataList) {
|
||||||
// save current to log
|
try {
|
||||||
ApplicationEntity curApplication = this.getById(id);
|
switch (format) {
|
||||||
this.saveApplcationToLog(curApplication);
|
case "tsg2402": {
|
||||||
// restore
|
List<ApplicationEntity> records = tsgApplicationService.tsg2402ToAsw(workspaceId, dataList);
|
||||||
ApplicationLogEntity oldApplication = applicationLogService.getOne(new LambdaQueryWrapper<ApplicationLogEntity>()
|
return records;
|
||||||
.eq(ApplicationLogEntity::getId, id)
|
|
||||||
.eq(ApplicationLogEntity::getOpVersion, version));
|
|
||||||
|
|
||||||
oldApplication.setUpdateTimestamp(System.currentTimeMillis());
|
|
||||||
oldApplication.setUpdateUserId(StpUtil.getLoginIdAsString());
|
|
||||||
oldApplication.setOpVersion(curApplication.getOpVersion() + 1);
|
|
||||||
|
|
||||||
ApplicationEntity application = T.BeanUtil.toBean(oldApplication, ApplicationEntity.class);
|
|
||||||
this.updateById(application);
|
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
/**
|
break;
|
||||||
* 1. 根据 workspace_name 查询 index-pattern 是否存在
|
|
||||||
* 2. 不存在则创建索引
|
|
||||||
*
|
|
||||||
* 维护格式示例:
|
|
||||||
* {
|
|
||||||
* "type": "index-pattern",
|
|
||||||
* "id": "workspace_id",
|
|
||||||
* "attributes": {
|
|
||||||
* "title": "workspace-{workspace_name}-*"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* @param workspaceId
|
|
||||||
* @param pcapIds
|
|
||||||
* @return kibana discover url
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String generateKibanaDiscoverUrl(String workspaceId, String pcapIds) {
|
|
||||||
// verify
|
|
||||||
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
|
||||||
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
|
||||||
|
|
||||||
List<String> pcapIdList = T.StrUtil.split(pcapIds, ",").stream().filter(s -> T.StrUtil.isNotEmpty(s)).collect(Collectors.toList());
|
|
||||||
List<PcapEntity> pcapList = pcapService.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, pcapIdList));
|
|
||||||
T.VerifyUtil.is(pcapList).notEmpty(RCode.SYS_RECORD_NOT_FOUND);
|
|
||||||
|
|
||||||
// index name
|
|
||||||
String indexName = String.format("workspace-%s-*", workspace.getName());
|
|
||||||
|
|
||||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
|
||||||
String token = tokenInfo.getTokenValue();
|
|
||||||
|
|
||||||
JSONObject index = kibanaClient.findIndexPattern(token, indexName);
|
|
||||||
JSONArray savedObjects = index.getJSONArray("saved_objects");
|
|
||||||
|
|
||||||
// check if index exists
|
|
||||||
boolean indexExists = savedObjects.stream()
|
|
||||||
.filter(obj -> {
|
|
||||||
JSONObject attributes = ((JSONObject) obj).getJSONObject("attributes");
|
|
||||||
if (T.ObjectUtil.isEmpty(attributes)) return false;
|
|
||||||
String title = attributes.getString("title");
|
|
||||||
return T.StrUtil.equals(indexName, title);
|
|
||||||
})
|
|
||||||
.findFirst()
|
|
||||||
.isPresent();
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("[generateKibanaDiscoverUrl] [idnex-pattern: {}] [exists: {}]", indexName, indexExists);
|
|
||||||
}
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
// create index
|
} catch (Exception e) {
|
||||||
if (T.BooleanUtil.negate(indexExists)) {
|
log.error(e, "[importAppByFormat] [error] [workspaceId: {}] [format: {}]", workspaceId, format);
|
||||||
JSONObject attributes = new JSONObject();
|
throw new ASWException(RCode.ERROR);
|
||||||
attributes.put("title", indexName);
|
|
||||||
|
|
||||||
JSONObject body = new JSONObject();
|
|
||||||
body.put("attributes", attributes);
|
|
||||||
kibanaClient.saveIndexPattern(token, workspaceId, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
// build url
|
|
||||||
String baseUrl = UrlBuilder.ofHttp(kibanaUrl)
|
|
||||||
.addPath("/app/data-explorer/discover")
|
|
||||||
.addQuery("jwt", token)
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
// build query param
|
|
||||||
String param1 = String.format("_a=(discover:(columns:!(_source),isDirty:!f,sort:!()),metadata:(indexPattern:'%s',view:discover))", workspaceId);
|
|
||||||
String param2 = "_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
|
||||||
|
|
||||||
String filter = pcapList.stream()
|
|
||||||
.map(PcapEntity::getId)
|
|
||||||
.map(pcapId -> "\"" + pcapId + "\"")
|
|
||||||
.collect(Collectors.joining("|", "pcap.id: (", ")"));
|
|
||||||
String param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s'))", filter);
|
|
||||||
|
|
||||||
String query = String.format("?%s&%s&%s", param1, param2, param3);
|
|
||||||
String kibanaDiscoverUrl = baseUrl + "#" + query;
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("[generateKibanaDiscoverUrl] [url: {}]", kibanaDiscoverUrl);
|
|
||||||
}
|
|
||||||
return kibanaDiscoverUrl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.dao.ApplicationSignatureDao;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationSignatureEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationSignatureService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApplicationSignatureServiceImpl extends ServiceImpl<ApplicationSignatureDao, ApplicationSignatureEntity> implements IApplicationSignatureService {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveSignature(ApplicationSignatureEntity signature, String applicationId) {
|
||||||
|
// query last note
|
||||||
|
ApplicationSignatureEntity signatureLast = this.queryLastVersionSignatureByAppId(applicationId);
|
||||||
|
|
||||||
|
if (T.ObjectUtil.isNotEmpty(signatureLast)){
|
||||||
|
signature.setOpVersion(signatureLast.getOpVersion() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save signature
|
||||||
|
signature.setApplicationId(applicationId);
|
||||||
|
signature.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
signature.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
|
this.save(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApplicationSignatureEntity> queryList(String applicationId) {
|
||||||
|
Map<Object, Object> params = T.MapUtil.builder().put("applicationId", applicationId).build();
|
||||||
|
List<ApplicationSignatureEntity> list = this.getBaseMapper().queryList(params);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApplicationSignatureEntity> compare(String applicationId, String oldVersion, String newVersion) {
|
||||||
|
|
||||||
|
List<String> versionList = Arrays.asList(oldVersion, newVersion);
|
||||||
|
Map<Object, Object> params = T.MapUtil.builder()
|
||||||
|
.put("applicationId", applicationId)
|
||||||
|
.put("versions", versionList)
|
||||||
|
.build();
|
||||||
|
List<ApplicationSignatureEntity> list = this.getBaseMapper().queryList(params);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restore(String applicationId, String version) {
|
||||||
|
ApplicationSignatureEntity signature = this.getOne(new LambdaQueryWrapper<ApplicationSignatureEntity>()
|
||||||
|
.eq(ApplicationSignatureEntity::getApplicationId, applicationId)
|
||||||
|
.eq(ApplicationSignatureEntity::getOpVersion, version));
|
||||||
|
ApplicationSignatureEntity lastSignature = this.queryLastVersionSignatureByAppId(applicationId);
|
||||||
|
if (T.ObjectUtil.isEmpty(signature)) {
|
||||||
|
throw ASWException.builder().rcode(RCode.APP_SIGNATURE_NOT_EXIST).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore
|
||||||
|
signature.setId(null);
|
||||||
|
signature.setOpVersion(lastSignature.getOpVersion() + 1);
|
||||||
|
this.save(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApplicationSignatureEntity queryLastVersionSignatureByAppId(String applicationId) {
|
||||||
|
ApplicationSignatureEntity entity = this.getOne(new LambdaQueryWrapper<ApplicationSignatureEntity>()
|
||||||
|
.eq(ApplicationSignatureEntity::getApplicationId, applicationId)
|
||||||
|
.orderByDesc(ApplicationSignatureEntity::getOpVersion)
|
||||||
|
.last("limit 1"));
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.service.IGitService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.StoredConfig;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GitServiceImpl implements IGitService {
|
||||||
|
|
||||||
|
private final static Log log = Log.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地分支引用前缀
|
||||||
|
*/
|
||||||
|
public static final String LOCAL_BRANCH_PREFIX = "refs/heads/";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get repository path
|
||||||
|
* path= {webRootPath}/workspeace/{workspace.name}
|
||||||
|
*/
|
||||||
|
private File getRepoDirPath(String workspaceId) {
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||||
|
File repoDir = T.FileUtil.file(T.WebPathUtil.getRootPath(), "workspeace", workspace.getName());
|
||||||
|
return repoDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get git instance
|
||||||
|
*/
|
||||||
|
private Git getGitInstance(File repoDir) {
|
||||||
|
try {
|
||||||
|
if (T.FileUtil.exist(repoDir) && T.FileUtil.file(repoDir, ".git").exists()) {
|
||||||
|
log.info("[getGitInstance] [open exist repository] [path: {}]", repoDir);
|
||||||
|
|
||||||
|
FileRepositoryBuilder builder = new FileRepositoryBuilder();
|
||||||
|
builder.setGitDir(T.FileUtil.file(repoDir, ".git"));
|
||||||
|
builder.readEnvironment();
|
||||||
|
builder.findGitDir();
|
||||||
|
|
||||||
|
return new Git(builder.build());
|
||||||
|
} else {
|
||||||
|
log.info("[getGitInstance] [init new repository] [path: {}]", repoDir);
|
||||||
|
// init
|
||||||
|
Git git = Git.init().setDirectory(repoDir).call();
|
||||||
|
// config
|
||||||
|
StoredConfig config = git.getRepository().getConfig();
|
||||||
|
config.setString("user", null, "name", "asw");
|
||||||
|
config.setString("user", null, "email", "asw@geedgenetworks.com");
|
||||||
|
config.save();
|
||||||
|
return git;
|
||||||
|
}
|
||||||
|
} catch (IOException | GitAPIException | IllegalStateException e) {
|
||||||
|
log.error(e, "[getGitInstance] [error] [path: {}]", repoDir);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<Object, Object>> listBranch(String workspaceId, String search) {
|
||||||
|
List<Map<Object, Object>> resultList = T.ListUtil.list(true);
|
||||||
|
|
||||||
|
File repoDir = this.getRepoDirPath(workspaceId);
|
||||||
|
try (Git git = this.getGitInstance(repoDir)) {
|
||||||
|
// List<Ref> call = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
|
||||||
|
|
||||||
|
// 默认行为,进查询本地分支
|
||||||
|
List<Ref> call = git.branchList().call();
|
||||||
|
RevWalk revCommits = new RevWalk(git.getRepository());
|
||||||
|
|
||||||
|
for (Ref ref : call) {
|
||||||
|
String branchName = ref.getName();
|
||||||
|
// 返回时去掉前缀
|
||||||
|
branchName = branchName.replaceAll(LOCAL_BRANCH_PREFIX, "");
|
||||||
|
if (T.StrUtil.isNotEmpty(search)) {
|
||||||
|
if (!T.StrUtil.contains(branchName, search)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("name", branchName)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RevCommit commit = revCommits.parseCommit(ref.getObjectId());
|
||||||
|
List<String> parentIds = Arrays.stream(commit.getParents()).map(RevCommit::getName).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<Object, Object> m1 = new LinkedHashMap<>();
|
||||||
|
m1.put("id", commit.getName());
|
||||||
|
m1.put("shortId", T.StrUtil.subPre(commit.getName(), 8));
|
||||||
|
m1.put("createdAt", commit.getCommitTime());
|
||||||
|
|
||||||
|
m1.put("title", commit.getShortMessage());
|
||||||
|
m1.put("message", commit.getFullMessage());
|
||||||
|
m1.put("parentIds", parentIds);
|
||||||
|
|
||||||
|
PersonIdent authorIdent = commit.getAuthorIdent();
|
||||||
|
m1.put("authorName", authorIdent.getName());
|
||||||
|
m1.put("authorEmail", authorIdent.getEmailAddress());
|
||||||
|
m1.put("authoredDate", authorIdent.getWhen().getTime());
|
||||||
|
|
||||||
|
PersonIdent committerIdent = commit.getCommitterIdent();
|
||||||
|
m1.put("committerName", committerIdent.getName());
|
||||||
|
m1.put("committerEmail", committerIdent.getEmailAddress());
|
||||||
|
m1.put("committedDate", committerIdent.getWhen().getTime());
|
||||||
|
|
||||||
|
m.put("commit", m1);
|
||||||
|
resultList.add(m);
|
||||||
|
}
|
||||||
|
} catch (GitAPIException | IOException e) {
|
||||||
|
log.error(e, "[listBranch] [error] [workspaceId: {}]", workspaceId);
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Object, Object> infoBranch(String workspaceId, String branchName) {
|
||||||
|
List<Map<Object, Object>> listBranch = this.listBranch(workspaceId, branchName);
|
||||||
|
|
||||||
|
// 分支不存在
|
||||||
|
if (T.CollUtil.isEmpty(listBranch)) {
|
||||||
|
throw new ASWException(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
}
|
||||||
|
return T.CollUtil.getFirst(listBranch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Object, Object> newBranch(String workspaceId, String branchName, String ref) {
|
||||||
|
File repoDir = this.getRepoDirPath(workspaceId);
|
||||||
|
try (Git git = this.getGitInstance(repoDir)) {
|
||||||
|
git.branchCreate()
|
||||||
|
.setName(branchName)
|
||||||
|
.setStartPoint(ref)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
return this.infoBranch(workspaceId, branchName);
|
||||||
|
} catch (GitAPIException e) {
|
||||||
|
log.error(e, "[newBranch] [error] [workspaceId: {}] [branchName: {}] [ref: {}]", workspaceId, branchName, ref);
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteBranch(String workspaceId, String branchName) {
|
||||||
|
File repoDir = this.getRepoDirPath(workspaceId);
|
||||||
|
try (Git git = this.getGitInstance(repoDir)) {
|
||||||
|
git.branchDelete()
|
||||||
|
.setBranchNames(branchName)
|
||||||
|
.call();
|
||||||
|
} catch (GitAPIException e) {
|
||||||
|
log.error(e, "[deleteBranch] [error] [workspaceId: {}] [branchName: {}]", workspaceId, branchName);
|
||||||
|
throw new ASWException(RCode.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,30 +1,63 @@
|
|||||||
package net.geedge.asw.module.app.service.impl;
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.dao.PackageDao;
|
import net.geedge.asw.module.app.dao.PackageDao;
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
import net.geedge.asw.module.app.service.IPackageService;
|
import net.geedge.asw.module.app.service.IPackageService;
|
||||||
|
import net.geedge.asw.module.app.util.ApkInfo;
|
||||||
|
import net.geedge.asw.module.app.util.ApkUtil;
|
||||||
|
import net.geedge.asw.module.app.util.PkgConstant;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||||
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
||||||
import net.geedge.asw.module.workbook.util.WorkbookConstant;
|
import net.geedge.asw.module.workbook.util.WorkbookConstant;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> implements IPackageService {
|
public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> implements IPackageService {
|
||||||
|
|
||||||
|
private final static Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysUserService sysUserService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IWorkbookResourceService workbookResourceService;
|
private IWorkbookResourceService workbookResourceService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PackageEntity queryInfo(String id) {
|
||||||
|
PackageEntity entity = this.getById(id);
|
||||||
|
T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
// user
|
||||||
|
SysUserEntity createUser = sysUserService.getById(entity.getCreateUserId());
|
||||||
|
SysUserEntity updateUser = sysUserService.getById(entity.getUpdateUserId());
|
||||||
|
|
||||||
|
createUser.setPwd(null);
|
||||||
|
updateUser.setPwd(null);
|
||||||
|
|
||||||
|
entity.setCreateUser(createUser);
|
||||||
|
entity.setUpdateUser(updateUser);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page queryList(Map<String, Object> params) {
|
public Page queryList(Map<String, Object> params) {
|
||||||
Page page = T.PageUtil.getPage(params);
|
Page page = T.PageUtil.getPage(params);
|
||||||
@@ -35,54 +68,70 @@ public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PackageEntity savePackage(PackageEntity entity) {
|
public PackageEntity savePackage(String workspaceId, String description, Resource fileResource) {
|
||||||
PackageEntity one = this.getOne(new LambdaQueryWrapper<PackageEntity>()
|
|
||||||
.eq(PackageEntity::getWorkspaceId, entity.getWorkspaceId())
|
|
||||||
.eq(PackageEntity::getName, entity.getName()));
|
|
||||||
if (T.ObjectUtil.isNotNull(one)) {
|
|
||||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
String pkgId = T.StrUtil.uuid();
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
String filename = fileResource.getFilename();
|
||||||
|
String suffix = T.FileUtil.extName(filename);
|
||||||
|
suffix = T.StrUtil.emptyToDefault(suffix, "apk");
|
||||||
|
if (!Constants.ANDROID_PACKAGE_TYPE_LIST.contains(suffix)) {
|
||||||
|
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
|
||||||
|
}
|
||||||
|
String saveFileName = pkgId + "." + suffix;
|
||||||
|
File destination = T.FileUtil.file(PkgConstant.APK_FILES_DIR, saveFileName);
|
||||||
|
PackageEntity entity = new PackageEntity();
|
||||||
|
ApkUtil apkUtil = new ApkUtil();
|
||||||
|
apkUtil.setAaptToolPath(Path.of(T.WebPathUtil.getRootPath(), "lib", "aapt").toString());
|
||||||
|
try {
|
||||||
|
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
|
||||||
|
if (suffix.equals("apk")) {
|
||||||
|
// parse
|
||||||
|
ApkInfo apkInfo = apkUtil.parseApk(destination.getPath());
|
||||||
|
if (T.ObjectUtil.isNull(apkInfo)) {
|
||||||
|
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
|
||||||
|
}
|
||||||
|
entity.setVersion(apkInfo.getVersionName());
|
||||||
|
entity.setIdentifier(apkInfo.getPackageName());
|
||||||
|
} else {
|
||||||
|
ApkInfo apkInfo = apkUtil.parseXapk(destination.getPath());
|
||||||
|
if (T.ObjectUtil.isNull(apkInfo)) {
|
||||||
|
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
|
||||||
|
}
|
||||||
|
entity.setVersion(apkInfo.getSdkVersion());
|
||||||
|
entity.setIdentifier(apkInfo.getPackageName());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[savePackage] [save package error] [file: {}]", fileResource.getFilename());
|
||||||
|
FileUtil.del(destination);
|
||||||
|
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
|
||||||
|
}
|
||||||
|
entity.setId(pkgId);
|
||||||
|
entity.setName(fileResource.getFilename());
|
||||||
|
entity.setDescription(T.StrUtil.emptyToDefault(description, ""));
|
||||||
|
entity.setPlatform(PkgConstant.Platform.ANDROID.getValue());
|
||||||
|
entity.setWorkspaceId(workspaceId);
|
||||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
// save
|
|
||||||
this.save(entity);
|
|
||||||
|
|
||||||
// workbook resource
|
|
||||||
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.PACKAGE.getValue());
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public PackageEntity updatePackage(PackageEntity entity) {
|
|
||||||
PackageEntity one = this.getOne(new LambdaQueryWrapper<PackageEntity>()
|
|
||||||
.eq(PackageEntity::getWorkspaceId, entity.getWorkspaceId())
|
|
||||||
.eq(PackageEntity::getName, entity.getName())
|
|
||||||
.ne(PackageEntity::getId, entity.getId()));
|
|
||||||
if (T.ObjectUtil.isNotNull(one)) {
|
|
||||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
entity.setSize(destination.length());
|
||||||
|
entity.setPath(destination.getPath());
|
||||||
// update
|
this.save(entity);
|
||||||
this.updateById(entity);
|
|
||||||
|
|
||||||
// workbook resource
|
|
||||||
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.PACKAGE.getValue());
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void removePackage(List<String> ids) {
|
public void removePackage(List<String> ids) {
|
||||||
|
for (String id : ids) {
|
||||||
|
PackageEntity entity = this.getById(id);
|
||||||
|
// remove file
|
||||||
|
T.FileUtil.del(entity.getPath());
|
||||||
|
|
||||||
// remove
|
// remove
|
||||||
this.removeBatchByIds(ids);
|
this.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
// workbook resource
|
// workbook resource
|
||||||
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue());
|
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package net.geedge.asw.module.app.service.impl;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
||||||
import net.geedge.asw.module.app.dao.SignatureDao;
|
|
||||||
import net.geedge.asw.module.app.entity.SignatureEntity;
|
|
||||||
import net.geedge.asw.module.app.service.ISignatureService;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class SignatureServiceImpl extends ServiceImpl<SignatureDao, SignatureEntity> implements ISignatureService {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,823 @@
|
|||||||
|
package net.geedge.asw.module.app.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.lang.Validator;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
|
import net.geedge.asw.module.app.entity.ApplicationSignatureEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationService;
|
||||||
|
import net.geedge.asw.module.app.service.IApplicationSignatureService;
|
||||||
|
import net.geedge.asw.module.app.service.ITSGApplicationService;
|
||||||
|
import net.geedge.asw.module.attribute.entity.AttributeEntity;
|
||||||
|
import net.geedge.asw.module.attribute.service.IAttributeService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TSGApplicationServiceImpl implements ITSGApplicationService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAttributeService attributeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationService applicationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IApplicationSignatureService applicationSignatureService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Object, Object> aswToTsg2402(List<ApplicationEntity> appList) {
|
||||||
|
|
||||||
|
List<Object> applications = this.buildTSG2402Applications(appList);
|
||||||
|
|
||||||
|
Map<Object, Object> signatures = this.buildTSG2402Signatures(appList);
|
||||||
|
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("applications", applications)
|
||||||
|
.putAll(signatures)
|
||||||
|
.build();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> buildTSG2402Applications(List<ApplicationEntity> appList) {
|
||||||
|
List<Object> applications = T.ListUtil.list(true);
|
||||||
|
for (ApplicationEntity app : appList) {
|
||||||
|
// application
|
||||||
|
Map<Object, Object> application = T.MapUtil.builder()
|
||||||
|
.put("app_name", app.getName())
|
||||||
|
.put("app_longname", app.getName())
|
||||||
|
.put("description", app.getDescription())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// app_properties
|
||||||
|
Map properties = (Map) app.getProperties();
|
||||||
|
Map<Object, Object> app_properties = T.MapUtil.builder()
|
||||||
|
.put("parent_app_id", 0)
|
||||||
|
.put("parent_app_name", "null")
|
||||||
|
.put("category", T.MapUtil.getStr(properties, "category", ""))
|
||||||
|
.put("subcategory", T.MapUtil.getStr(properties, "subcategory", ""))
|
||||||
|
.put("content", T.MapUtil.getStr(properties, "content", ""))
|
||||||
|
.put("risk", T.MapUtil.getStr(properties, "risk", "1"))
|
||||||
|
.put("characteristics", T.MapUtil.getStr(properties, "characteristics", ""))
|
||||||
|
.put("deny_action", T.MapUtil.builder()
|
||||||
|
.put("method", "drop")
|
||||||
|
.put("after_n_packets", 0)
|
||||||
|
.put("send_icmp_unreachable", 0)
|
||||||
|
.put("send_tcp_reset", 0)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.put("continue_scanning", 0)
|
||||||
|
.put("tcp_timeout", 0)
|
||||||
|
.put("udp_timeout", 0)
|
||||||
|
.put("tcp_half_close", 0)
|
||||||
|
.put("tcp_time_wait", 0)
|
||||||
|
.build();
|
||||||
|
application.put("app_properties", app_properties);
|
||||||
|
|
||||||
|
// app_surrogates
|
||||||
|
ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId());
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent());
|
||||||
|
JSONArray surrogates = jsonObject.getJSONArray("surrogates");
|
||||||
|
if (!surrogates.isEmpty()) {
|
||||||
|
List<Map> app_surrogates = T.ListUtil.list(true);
|
||||||
|
surrogates.forEach(obj -> {
|
||||||
|
List<Object> signature_sequence = T.ListUtil.list(true);
|
||||||
|
|
||||||
|
JSONArray signatureArr = ((JSONObject) obj).getJSONArray("signatures");
|
||||||
|
signatureArr.stream().map(o -> ((JSONObject) o).getStr("name")).forEach(tname -> {
|
||||||
|
signature_sequence.add(T.MapUtil.builder()
|
||||||
|
.put("signature", tname)
|
||||||
|
.put("exclude", 0)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
app_surrogates.add(
|
||||||
|
T.MapUtil.builder()
|
||||||
|
.put("group_by", "session")
|
||||||
|
.put("time_window", 0)
|
||||||
|
.put("ordered_match", "no")
|
||||||
|
.put("signature_sequence", signature_sequence)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
application.put("app_surrogates", app_surrogates);
|
||||||
|
}
|
||||||
|
applications.add(application);
|
||||||
|
}
|
||||||
|
return applications;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Object, Object> buildTSG2402Signatures(List<ApplicationEntity> appList) {
|
||||||
|
List<Object> signatures = T.ListUtil.list(true);
|
||||||
|
List<Object> sig_objects = T.ListUtil.list(true);
|
||||||
|
|
||||||
|
int sig_object_id = 10, signature_id = 0;
|
||||||
|
for (ApplicationEntity app : appList) {
|
||||||
|
ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId());
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent());
|
||||||
|
JSONArray surrogates = jsonObject.getJSONArray("surrogates");
|
||||||
|
List<Object> signaturesForApp = surrogates.stream()
|
||||||
|
.map(obj -> ((JSONObject) obj).getJSONArray("signatures"))
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
for (Object object : signaturesForApp) {
|
||||||
|
JSONObject surrogate = (JSONObject) object;
|
||||||
|
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("signature_id", signature_id++)
|
||||||
|
.put("signature_name", T.MapUtil.getStr(surrogate, "name"))
|
||||||
|
.put("signature_desc", T.MapUtil.getStr(surrogate, "description", ""))
|
||||||
|
.put("icon_color", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Object> and_conditions = T.ListUtil.list(true);
|
||||||
|
JSONArray conditions = surrogate.getJSONArray("conditions");
|
||||||
|
for (Object condition : conditions) {
|
||||||
|
JSONObject conditionJSONObj = (JSONObject) condition;
|
||||||
|
|
||||||
|
String attributeType = T.MapUtil.getStr(conditionJSONObj, "attributeType");
|
||||||
|
String attributeName = T.MapUtil.getStr(conditionJSONObj, "attributeName");
|
||||||
|
AttributeEntity attributeEntity = attributeService.queryAttribute(attributeType, attributeName);
|
||||||
|
if (null == attributeEntity || T.StrUtil.isEmpty(attributeEntity.getObjectType())) continue;
|
||||||
|
|
||||||
|
Map<Object, Object> or_condition_obj = T.MapUtil.builder()
|
||||||
|
.put("lua_profile_id", 0)
|
||||||
|
.put("attribute_type", attributeType)
|
||||||
|
.put("attribute_name", attributeName)
|
||||||
|
.put("protocol", attributeEntity.getProtocol())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Integer> source_object_ids = T.ListUtil.list(true);
|
||||||
|
|
||||||
|
// sig_objects
|
||||||
|
JSONArray items = conditionJSONObj.getJSONArray("items");
|
||||||
|
|
||||||
|
String conditionType = attributeEntity.getObjectType();
|
||||||
|
if ("application".equalsIgnoreCase(conditionType)) {
|
||||||
|
continue;
|
||||||
|
} else if ("boolean".equals(conditionType)) {
|
||||||
|
items.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String itemValue = T.MapUtil.getStr((JSONObject) item, "item");
|
||||||
|
if ("True".equalsIgnoreCase(itemValue)) {
|
||||||
|
source_object_ids.add(2);
|
||||||
|
} else if ("False".equalsIgnoreCase(itemValue)) {
|
||||||
|
source_object_ids.add(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ("ip_protocol".equals(conditionType)) {
|
||||||
|
items.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String itemValue = T.MapUtil.getStr((JSONObject) item, "item");
|
||||||
|
if ("ICMP".equalsIgnoreCase(itemValue)) {
|
||||||
|
source_object_ids.add(5);
|
||||||
|
} else if ("TCP".equalsIgnoreCase(itemValue)) {
|
||||||
|
source_object_ids.add(6);
|
||||||
|
} else if ("UDP".equalsIgnoreCase(itemValue)) {
|
||||||
|
source_object_ids.add(7);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
String name = T.MapUtil.getStr((JSONObject) items.getFirst(), "item");
|
||||||
|
Map<Object, Object> sig_object = T.MapUtil.builder()
|
||||||
|
.put("id", sig_object_id)
|
||||||
|
.put("source_id", sig_object_id)
|
||||||
|
.put("name", name)
|
||||||
|
.put("source_name", name)
|
||||||
|
.put("type", conditionType)
|
||||||
|
.put("sub_type", attributeEntity.getType())
|
||||||
|
.put("member_type", "item")
|
||||||
|
.put("uuid", T.IdUtil.fastSimpleUUID())
|
||||||
|
.put("statistics_option", "none")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<Object, Object> member = this.buildTSG2402SignaturesMember(attributeEntity, items);
|
||||||
|
sig_object.put("member", member);
|
||||||
|
|
||||||
|
sig_objects.add(sig_object);
|
||||||
|
source_object_ids.add(sig_object_id);
|
||||||
|
sig_object_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
or_condition_obj.put("source_object_ids", source_object_ids);
|
||||||
|
Map<Object, Object> and_condition_item = T.MapUtil.builder()
|
||||||
|
.put("not_flag", T.MapUtil.getBool(conditionJSONObj, "negate_option", false) ? 1 : 0)
|
||||||
|
.put("or_conditions", T.ListUtil.of(or_condition_obj))
|
||||||
|
.build();
|
||||||
|
and_conditions.add(and_condition_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.CollUtil.isNotEmpty(and_conditions)) {
|
||||||
|
m.put("and_conditions", and_conditions);
|
||||||
|
signatures.add(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig_objects.add(T.JSONUtil.parseObj("""
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "boolean",
|
||||||
|
"name": "True",
|
||||||
|
"vsys_id": 0,
|
||||||
|
"description": "True",
|
||||||
|
"source_id": 2,
|
||||||
|
"source_name": "True",
|
||||||
|
"member_type": "item",
|
||||||
|
"uuid": "c4ca4238a0b923820dcc509a6f75849b",
|
||||||
|
"statistics_option": "elaborate"
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
sig_objects.add(T.JSONUtil.parseObj("""
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"type": "boolean",
|
||||||
|
"name": "False",
|
||||||
|
"vsys_id": 0,
|
||||||
|
"description": "False",
|
||||||
|
"source_id": 3,
|
||||||
|
"source_name": "False",
|
||||||
|
"member_type": "item",
|
||||||
|
"uuid": "cfcd208495d565ef66e7dff9f98764da",
|
||||||
|
"statistics_option": "elaborate"
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
sig_objects.add(T.JSONUtil.parseObj("""
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "ip_protocol",
|
||||||
|
"name": "ICMP",
|
||||||
|
"vsys_id": 0,
|
||||||
|
"description": "ICMP",
|
||||||
|
"source_id": 5,
|
||||||
|
"source_name": "ICMP",
|
||||||
|
"member_type": "item",
|
||||||
|
"uuid": "c4ca4238a0b923820dcc509a6f75849b",
|
||||||
|
"statistics_option": "elaborate"
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
sig_objects.add(T.JSONUtil.parseObj("""
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "ip_protocol",
|
||||||
|
"name": "TCP",
|
||||||
|
"vsys_id": 0,
|
||||||
|
"description": "TCP",
|
||||||
|
"source_id": 6,
|
||||||
|
"source_name": "TCP",
|
||||||
|
"member_type": "item",
|
||||||
|
"uuid": "1679091c5a880faf6fb5e6087eb1b2dc",
|
||||||
|
"statistics_option": "elaborate"
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
sig_objects.add(T.JSONUtil.parseObj("""
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"type": "ip_protocol",
|
||||||
|
"name": "UDP",
|
||||||
|
"vsys_id": 0,
|
||||||
|
"description": "UDP",
|
||||||
|
"source_id": 7,
|
||||||
|
"source_name": "UDP",
|
||||||
|
"member_type": "item",
|
||||||
|
"uuid": "70efdf2ec9b086079795c442636b55fb",
|
||||||
|
"statistics_option": "elaborate"
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("signatures", signatures)
|
||||||
|
.put("sig_objects", sig_objects)
|
||||||
|
.build();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Object, Object> buildTSG2402SignaturesMember(AttributeEntity attributeEntity, JSONArray itemArr) {
|
||||||
|
List<Object> list = T.ListUtil.list(true);
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String objectType = attributeEntity.getObjectType().toLowerCase();
|
||||||
|
switch (objectType) {
|
||||||
|
case "keywords":
|
||||||
|
case "http_signature": {
|
||||||
|
String str = item.getStr("item");
|
||||||
|
List<String> patternExprList = T.ListUtil.list(true);
|
||||||
|
patternExprList.add(str);
|
||||||
|
|
||||||
|
// 0 -> 无表达式,1 -> 与表达式,2 -> 正则表达式,3、带偏移量的子串匹配
|
||||||
|
int expr_type = 0;
|
||||||
|
String exprType = item.getStr("exprType", "and");
|
||||||
|
if ("and".equalsIgnoreCase(exprType)) {
|
||||||
|
patternExprList = T.StrUtil.split(str, "&");
|
||||||
|
if (patternExprList.size() > 1) {
|
||||||
|
expr_type = 1;
|
||||||
|
}
|
||||||
|
} else if ("regex".equalsIgnoreCase(exprType)) {
|
||||||
|
expr_type = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray patternArr = new JSONArray();
|
||||||
|
for (String expr : patternExprList) {
|
||||||
|
JSONObject pattern = new JSONObject();
|
||||||
|
pattern.put("keywords", expr);
|
||||||
|
|
||||||
|
Map<String, String> rangeVarMap = this.getRangeVarFromExpr(expr);
|
||||||
|
if (T.MapUtil.isNotEmpty(rangeVarMap)) {
|
||||||
|
expr_type = 3;
|
||||||
|
pattern.put("keywords", expr.replaceAll("^\\(.*?\\)", ""));
|
||||||
|
pattern.put("offset", T.MapUtil.getInt(rangeVarMap, "offset"));
|
||||||
|
pattern.put("depth", T.MapUtil.getInt(rangeVarMap, "depth"));
|
||||||
|
}
|
||||||
|
patternArr.add(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("keywords".equals(objectType)) {
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("string", T.MapUtil.builder()
|
||||||
|
.put("item_type", "keywords")
|
||||||
|
.put("expr_type", expr_type)
|
||||||
|
.put("is_hexbin", 0)
|
||||||
|
.put("patterns", patternArr)
|
||||||
|
.build()
|
||||||
|
).build();
|
||||||
|
list.add(m);
|
||||||
|
}
|
||||||
|
if ("http_signature".equals(objectType)) {
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("contextual_string", T.MapUtil.builder()
|
||||||
|
.put("expr_type", expr_type)
|
||||||
|
.put("is_hexbin", 0)
|
||||||
|
.put("context_name", item.getStr("district", "Set-Cookie"))
|
||||||
|
.put("patterns", patternArr)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
list.add(m);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "url":
|
||||||
|
case "fqdn": {
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("string", T.MapUtil.builder()
|
||||||
|
.put("item_type", objectType)
|
||||||
|
.put("expr_type", 0)
|
||||||
|
.put("is_hexbin", 0)
|
||||||
|
.put("patterns", T.ListUtil.of(
|
||||||
|
new JSONObject().put("keywords", item.getStr("item"))
|
||||||
|
))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
list.add(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "ip": {
|
||||||
|
String str = item.getStr("item");
|
||||||
|
String ip = str;
|
||||||
|
String port = "0-65535";
|
||||||
|
if (str.contains("#")) {
|
||||||
|
ip = str.split("#")[0];
|
||||||
|
port = str.split("#")[1];
|
||||||
|
}
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("ip", T.MapUtil.builder()
|
||||||
|
.put("addr_type", Validator.isIpv4(str) ? 4 : 6)
|
||||||
|
.put("port", port)
|
||||||
|
.put("ip_address", ip)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
list.add(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "port": {
|
||||||
|
String port = item.getStr("item");
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("port", new JSONObject().put("port", port))
|
||||||
|
.build();
|
||||||
|
if (port.contains("-")) {
|
||||||
|
m.put("port", new JSONObject().put("port_range", port));
|
||||||
|
}
|
||||||
|
list.add(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "interval": {
|
||||||
|
String str = item.getStr("item");
|
||||||
|
String low_boundary = str, up_boundary = str;
|
||||||
|
if (str.contains("-")) {
|
||||||
|
low_boundary = item.getStr("item").split("-")[0];
|
||||||
|
up_boundary = item.getStr("item").split("-")[1];
|
||||||
|
}
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("interval", T.MapUtil.builder()
|
||||||
|
.put("low_boundary", low_boundary)
|
||||||
|
.put("up_boundary", up_boundary)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
list.add(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "boolean":
|
||||||
|
case "ip_protocol":
|
||||||
|
case "application": {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<Object, Object> member = T.MapUtil.builder()
|
||||||
|
.put("items", list)
|
||||||
|
.build();
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取表达式中的 range 变量,示例 (nocase=off,offset=6,depth=13)expr_xxxxxxxxx
|
||||||
|
*/
|
||||||
|
private Map<String, String> getRangeVarFromExpr(String expr) {
|
||||||
|
try {
|
||||||
|
String regex = "^\\(([^)]+)\\)";
|
||||||
|
String str = T.ReUtil.get(regex, expr, 1);
|
||||||
|
if (T.StrUtil.isNotEmpty(str)) {
|
||||||
|
String[] pairs = str.split(",");
|
||||||
|
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
for (String pair : pairs) {
|
||||||
|
String[] keyValue = pair.split("=");
|
||||||
|
if (keyValue.length == 2) {
|
||||||
|
map.put(keyValue[0].trim(), keyValue[1].trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 不包含 offset,depth 算没有配置
|
||||||
|
if (!map.containsKey("offset") || !map.containsKey("depth")) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[getRangeVarFromExpr] [expr: {}]", expr);
|
||||||
|
}
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public List<ApplicationEntity> tsg2402ToAsw(String workspaceId, List<JSONObject> dataList) {
|
||||||
|
List<ApplicationEntity> records = T.ListUtil.list(true);
|
||||||
|
for (JSONObject tsgAppSourceData : dataList) {
|
||||||
|
|
||||||
|
JSONArray all_application = tsgAppSourceData.getJSONArray("applications");
|
||||||
|
JSONArray all_signature = tsgAppSourceData.getJSONArray("signatures");
|
||||||
|
JSONArray all_sig_object = tsgAppSourceData.getJSONArray("sig_objects");
|
||||||
|
|
||||||
|
all_application.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(application -> {
|
||||||
|
// application
|
||||||
|
String app_name = application.getStr("app_name");
|
||||||
|
String description = application.getStr("description");
|
||||||
|
|
||||||
|
JSONObject appProperties = application.getJSONObject("app_properties");
|
||||||
|
String category = T.MapUtil.getStr(appProperties, "category", "");
|
||||||
|
String subcategory = T.MapUtil.getStr(appProperties, "subcategory", "");
|
||||||
|
String content = T.MapUtil.getStr(appProperties, "content", "");
|
||||||
|
int risk = T.MapUtil.getInt(appProperties, "risk", 1);
|
||||||
|
String characteristics = T.MapUtil.getStr(appProperties, "characteristics", "");
|
||||||
|
|
||||||
|
Map<Object, Object> properties = T.MapUtil.builder()
|
||||||
|
.put("category", category)
|
||||||
|
.put("subcategory", subcategory)
|
||||||
|
.put("content", content)
|
||||||
|
.put("risk", risk)
|
||||||
|
.put("characteristics", characteristics)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// save or update application
|
||||||
|
ApplicationEntity entity = new ApplicationEntity();
|
||||||
|
entity.setName(app_name);
|
||||||
|
entity.setDescription(description);
|
||||||
|
entity.setProperties(properties);
|
||||||
|
entity.setPackageName("{}");
|
||||||
|
entity.setWorkspaceId(workspaceId);
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
|
ApplicationEntity one = applicationService.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
||||||
|
.eq(ApplicationEntity::getWorkspaceId, workspaceId)
|
||||||
|
.eq(ApplicationEntity::getName, app_name));
|
||||||
|
if (null != one) {
|
||||||
|
entity.setId(one.getId());
|
||||||
|
}
|
||||||
|
applicationService.saveOrUpdate(entity);
|
||||||
|
|
||||||
|
records.add(entity);
|
||||||
|
String applicationId = entity.getId();
|
||||||
|
|
||||||
|
// surrogate - signature
|
||||||
|
Map<String, List<String>> surrAndSignListMap = T.MapUtil.newHashMap();
|
||||||
|
JSONArray app_surrogates = application.getJSONArray("app_surrogates");
|
||||||
|
if (T.ObjectUtil.isNotEmpty(app_surrogates)) {
|
||||||
|
for (int i = 0; i < app_surrogates.size(); i++) {
|
||||||
|
JSONObject surrogate = (JSONObject) app_surrogates.get(i);
|
||||||
|
List<String> signatureNameList = (List<String>) T.JSONUtil.getByPath(surrogate, "signature_sequence.signature");
|
||||||
|
surrAndSignListMap.put("surrogate_" + (i + 1), signatureNameList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<Object> insertSurrogateList = T.ListUtil.list(true);
|
||||||
|
for (Map.Entry<String, List<String>> entry : surrAndSignListMap.entrySet()) {
|
||||||
|
String surrogateName = entry.getKey();
|
||||||
|
|
||||||
|
List<String> signatureNameList = entry.getValue();
|
||||||
|
List<JSONObject> signatureListInApp = all_signature.stream()
|
||||||
|
.filter(obj -> {
|
||||||
|
String str = T.MapUtil.getStr((JSONObject) obj, "signature_name", "");
|
||||||
|
return signatureNameList.contains(str);
|
||||||
|
})
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (T.CollUtil.isEmpty(signatureListInApp)) continue;
|
||||||
|
|
||||||
|
List<JSONObject> sigObjectList = all_sig_object.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Object, Object> aswSrrogate = this.buildAswSurrogateFromTSG2402(surrogateName, signatureListInApp, sigObjectList);
|
||||||
|
insertSurrogateList.add(aswSrrogate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Object, Object> sm = T.MapUtil.builder()
|
||||||
|
.put("surrogates", insertSurrogateList)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// save application signatrue
|
||||||
|
ApplicationSignatureEntity signatureEntity = new ApplicationSignatureEntity();
|
||||||
|
signatureEntity.setApplicationId(applicationId);
|
||||||
|
signatureEntity.setContent(T.JSONUtil.toJsonStr(sm));
|
||||||
|
signatureEntity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
signatureEntity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
signatureEntity.setOpVersion(0L);
|
||||||
|
|
||||||
|
ApplicationSignatureEntity signatureLast = applicationSignatureService.queryLastVersionSignatureByAppId(applicationId);
|
||||||
|
if (T.ObjectUtil.isNotEmpty(signatureLast)) {
|
||||||
|
signatureEntity.setOpVersion(signatureLast.getOpVersion() + 1);
|
||||||
|
}
|
||||||
|
applicationSignatureService.save(signatureEntity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Object, Object> buildAswSurrogateFromTSG2402(String surrogateName, List<JSONObject> signatureList, List<JSONObject> sigObjectList) {
|
||||||
|
// surrogate
|
||||||
|
Map<Object, Object> surrogate = T.MapUtil.builder()
|
||||||
|
.put("name", surrogateName)
|
||||||
|
.put("description", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// signatures
|
||||||
|
List<Object> signatures = T.ListUtil.list(true);
|
||||||
|
for (JSONObject jsonObject : signatureList) {
|
||||||
|
String signature_name = jsonObject.getStr("signature_name");
|
||||||
|
String signature_description = jsonObject.getStr("signature_desc");
|
||||||
|
|
||||||
|
Map<Object, Object> signMap = T.MapUtil.builder()
|
||||||
|
.put("name", signature_name)
|
||||||
|
.put("description", signature_description)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// conditions
|
||||||
|
List<Map<Object, Object>> conditionMapList = T.ListUtil.list(true);
|
||||||
|
|
||||||
|
JSONArray and_conditions = jsonObject.getJSONArray("and_conditions");
|
||||||
|
for (Object obj : and_conditions) {
|
||||||
|
JSONObject conditions = (JSONObject) obj;
|
||||||
|
// base field
|
||||||
|
Integer not_flag = conditions.getInt("not_flag", 0);
|
||||||
|
|
||||||
|
JSONObject or_condition = (JSONObject) T.JSONUtil.getByPath(conditions, "or_conditions[0]");
|
||||||
|
String attribute_name = or_condition.getStr("attribute_name", "");
|
||||||
|
String attribute_type = or_condition.getStr("attribute_type", "");
|
||||||
|
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("attributeName", attribute_name)
|
||||||
|
.put("attributeType", attribute_type)
|
||||||
|
.put("negate_option", not_flag == 1 ? true : false)
|
||||||
|
.put("description", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// items
|
||||||
|
List<Integer> source_object_ids = (List<Integer>) T.JSONUtil.getByPath(or_condition, "source_object_ids");
|
||||||
|
if (T.CollUtil.isEmpty(source_object_ids)) continue;
|
||||||
|
|
||||||
|
List<JSONObject> sourceObjectList = sigObjectList.stream()
|
||||||
|
.filter(entries -> {
|
||||||
|
Integer anInt = entries.getInt("id");
|
||||||
|
return source_object_ids.contains(anInt);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Map<Object, Object>> itemList = this.buildAswConditionItemsFromTSG2402(sourceObjectList);
|
||||||
|
if (T.CollUtil.isEmpty(itemList)) continue;
|
||||||
|
|
||||||
|
// 按 item value 去重
|
||||||
|
List<Map<String, String>> distinctItemList = itemList.stream()
|
||||||
|
.collect(Collectors.collectingAndThen(
|
||||||
|
Collectors.toMap(
|
||||||
|
map -> map.get("item"),
|
||||||
|
map -> map,
|
||||||
|
(existing, replacement) -> existing // 保留第一个出现的元素
|
||||||
|
),
|
||||||
|
map -> new ArrayList(map.values())
|
||||||
|
));
|
||||||
|
m.put("items", distinctItemList);
|
||||||
|
conditionMapList.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
signMap.put("conditions", conditionMapList);
|
||||||
|
signatures.add(signMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
surrogate.put("signatures", signatures);
|
||||||
|
return surrogate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Map<Object, Object>> buildAswConditionItemsFromTSG2402(List<JSONObject> sourceObjectList) {
|
||||||
|
List<Map<Object, Object>> iiemList = T.ListUtil.list(true);
|
||||||
|
for (JSONObject jsonObject : sourceObjectList) {
|
||||||
|
|
||||||
|
String type = jsonObject.getStr("type");
|
||||||
|
JSONArray itemArr = (JSONArray) T.JSONUtil.getByPath(jsonObject, "member.items");
|
||||||
|
itemArr = T.CollUtil.defaultIfEmpty(itemArr, new JSONArray());
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "http_signature":
|
||||||
|
case "keywords": {
|
||||||
|
String exprTypeJsonPath = "keywords" .equals(type) ? "string.expr_type" : "contextual_string.expr_type";
|
||||||
|
String firstExprJsonPath = "keywords" .equals(type) ? "string.patterns[0].keywords" : "contextual_string.patterns[0].keywords";
|
||||||
|
String patternsJsonPath = "keywords" .equals(type) ? "string.patterns" : "contextual_string.patterns";
|
||||||
|
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
// 0 -> 无表达式,1 -> 与表达式,2 -> 正则表达式,3、带偏移量的子串匹配
|
||||||
|
Integer expr_type = (Integer) T.JSONUtil.getByPath(item, exprTypeJsonPath);
|
||||||
|
|
||||||
|
String tempType = "and";
|
||||||
|
String expr = (String) T.JSONUtil.getByPath(item, firstExprJsonPath);
|
||||||
|
switch (expr_type) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
JSONArray patterns = (JSONArray) T.JSONUtil.getByPath(item, patternsJsonPath);
|
||||||
|
expr = patterns.stream()
|
||||||
|
.map(obj -> ((JSONObject) obj).getStr("keywords"))
|
||||||
|
.collect(Collectors.joining("&"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
tempType = "regex";
|
||||||
|
break;
|
||||||
|
case 3: {
|
||||||
|
JSONArray patterns = (JSONArray) T.JSONUtil.getByPath(item, patternsJsonPath);
|
||||||
|
expr = patterns.stream()
|
||||||
|
.map(obj -> {
|
||||||
|
String keywords = ((JSONObject) obj).getStr("keywords");
|
||||||
|
String offset = ((JSONObject) obj).getStr("offset");
|
||||||
|
String depth = ((JSONObject) obj).getStr("depth");
|
||||||
|
return T.StrUtil.concat(true, "(offset=", offset, ",depth=", depth, ")", keywords);
|
||||||
|
})
|
||||||
|
.collect(Collectors.joining("&"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("item", expr)
|
||||||
|
.put("exprType", tempType)
|
||||||
|
.put("description", "")
|
||||||
|
.build();
|
||||||
|
String context_name = (String) T.JSONUtil.getByPath(item, "contextual_string.context_name");
|
||||||
|
if (T.StrUtil.isNotEmpty(context_name)) {
|
||||||
|
m.put("district", context_name);
|
||||||
|
}
|
||||||
|
iiemList.add(m);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "url":
|
||||||
|
case "fqdn": {
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String str = (String) T.JSONUtil.getByPath(item, "string.patterns[0].keywords");
|
||||||
|
iiemList.add(
|
||||||
|
T.MapUtil.builder()
|
||||||
|
.put("item", str)
|
||||||
|
.put("description", "")
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "ip": {
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String port = (String) T.JSONUtil.getByPath(item, "ip.port");
|
||||||
|
String ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_address");
|
||||||
|
if (T.StrUtil.isEmpty(ipAddress)) {
|
||||||
|
ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_cidr");
|
||||||
|
}
|
||||||
|
if (T.StrUtil.isEmpty(ipAddress)) {
|
||||||
|
ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_range");
|
||||||
|
}
|
||||||
|
if (!"0-65535" .equalsIgnoreCase(port)) {
|
||||||
|
ipAddress = T.StrUtil.concat(true, ipAddress, "#", port);
|
||||||
|
}
|
||||||
|
iiemList.add(
|
||||||
|
T.MapUtil.builder()
|
||||||
|
.put("item", ipAddress)
|
||||||
|
.put("description", "")
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "port": {
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
String port = (String) T.JSONUtil.getByPath(item, "port.port");
|
||||||
|
if (T.StrUtil.isEmpty(port)) {
|
||||||
|
port = (String) T.JSONUtil.getByPath(item, "port.port_range");
|
||||||
|
}
|
||||||
|
iiemList.add(
|
||||||
|
T.MapUtil.builder()
|
||||||
|
.put("item", port)
|
||||||
|
.put("description", "")
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "interval": {
|
||||||
|
itemArr.stream()
|
||||||
|
.map(obj -> (JSONObject) obj)
|
||||||
|
.forEach(item -> {
|
||||||
|
Object low_boundary = T.JSONUtil.getByPath(item, "interval.low_boundary");
|
||||||
|
Object up_boundary = T.JSONUtil.getByPath(item, "interval.up_boundary");
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("item", low_boundary + "-" + up_boundary)
|
||||||
|
.put("description", "")
|
||||||
|
.build();
|
||||||
|
iiemList.add(m);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "boolean":
|
||||||
|
case "ip_protocol": {
|
||||||
|
Map<Object, Object> m = T.MapUtil.builder()
|
||||||
|
.put("item", jsonObject.getStr("name"))
|
||||||
|
.put("description", "")
|
||||||
|
.build();
|
||||||
|
iiemList.add(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "application": {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iiemList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
169
src/main/java/net/geedge/asw/module/app/util/ApkInfo.java
Normal file
169
src/main/java/net/geedge/asw/module/app/util/ApkInfo.java
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package net.geedge.asw.module.app.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ApkInfo {
|
||||||
|
|
||||||
|
public static final String APPLICATION_ICON_120 = "application-icon-120";
|
||||||
|
public static final String APPLICATION_ICON_160 = "application-icon-160";
|
||||||
|
public static final String APPLICATION_ICON_240 = "application-icon-240";
|
||||||
|
public static final String APPLICATION_ICON_320 = "application-icon-320";
|
||||||
|
|
||||||
|
// 所需设备属性
|
||||||
|
private List<String> features;
|
||||||
|
// 图标
|
||||||
|
private String icon;
|
||||||
|
// 各分辨率下图标路径
|
||||||
|
private Map<String, String> icons;
|
||||||
|
// 应用程序名
|
||||||
|
private String label;
|
||||||
|
// 入口Activity
|
||||||
|
private String launchableActivity;
|
||||||
|
// 支持的Android平台最低版本号
|
||||||
|
private String minSdkVersion;
|
||||||
|
// 主包名
|
||||||
|
private String packageName;
|
||||||
|
// 支持的SDK版本
|
||||||
|
private String sdkVersion;
|
||||||
|
// Apk文件大小(字节)
|
||||||
|
private long size;
|
||||||
|
// 目标SDK版本
|
||||||
|
private String targetSdkVersion;
|
||||||
|
// 所需权限
|
||||||
|
private List<String> usesPermissions;
|
||||||
|
// 内部版本号
|
||||||
|
private String versionCode;
|
||||||
|
// 外部版本号
|
||||||
|
private String versionName;
|
||||||
|
|
||||||
|
public ApkInfo() {
|
||||||
|
this.features = new ArrayList<>();
|
||||||
|
this.icons = new HashMap<>();
|
||||||
|
this.usesPermissions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getFeatures() {
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeatures(List<String> features) {
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToFeatures(String feature) {
|
||||||
|
this.features.add(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(String icon) {
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getIcons() {
|
||||||
|
return icons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcons(Map<String, String> icons) {
|
||||||
|
this.icons = icons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToIcons(String key, String value) {
|
||||||
|
this.icons.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLaunchableActivity() {
|
||||||
|
return launchableActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLaunchableActivity(String launchableActivity) {
|
||||||
|
this.launchableActivity = launchableActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinSdkVersion() {
|
||||||
|
return minSdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinSdkVersion(String minSdkVersion) {
|
||||||
|
this.minSdkVersion = minSdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPackageName() {
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageName(String packageName) {
|
||||||
|
this.packageName = packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSdkVersion() {
|
||||||
|
return sdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSdkVersion(String sdkVersion) {
|
||||||
|
this.sdkVersion = sdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(long size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetSdkVersion() {
|
||||||
|
return targetSdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetSdkVersion(String targetSdkVersion) {
|
||||||
|
this.targetSdkVersion = targetSdkVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getUsesPermissions() {
|
||||||
|
return usesPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsesPermissions(List<String> usesPermissions) {
|
||||||
|
this.usesPermissions = usesPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToUsesPermissions(String usesPermission) {
|
||||||
|
this.usesPermissions.add(usesPermission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersionCode() {
|
||||||
|
return versionCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersionCode(String versionCode) {
|
||||||
|
this.versionCode = versionCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersionName() {
|
||||||
|
return versionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersionName(String versionName) {
|
||||||
|
this.versionName = versionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ApkInfo [features=" + features + ", icon=" + icon + ", icons=" + icons + ", label=" + label + ", launchableActivity=" + launchableActivity + ", minSdkVersion=" + minSdkVersion + ", packageName=" + packageName + ", sdkVersion=" + sdkVersion + ", size=" + size + ", targetSdkVersion=" + targetSdkVersion + ", usesPermissions=" + usesPermissions + ", versionCode=" + versionCode + ", versionName=" + versionName + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
155
src/main/java/net/geedge/asw/module/app/util/ApkUtil.java
Normal file
155
src/main/java/net/geedge/asw/module/app/util/ApkUtil.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package net.geedge.asw.module.app.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class ApkUtil {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
public static final String APPLICATION = "application:";
|
||||||
|
public static final String APPLICATION_ICON = "application-icon";
|
||||||
|
public static final String APPLICATION_LABEL = "application-label";
|
||||||
|
public static final String APPLICATION_LABEL_N = "application: label";
|
||||||
|
public static final String DENSITIES = "densities";
|
||||||
|
public static final String LAUNCHABLE_ACTIVITY = "launchable";
|
||||||
|
public static final String PACKAGE = "package";
|
||||||
|
public static final String SDK_VERSION = "sdkVersion";
|
||||||
|
public static final String SUPPORTS_ANY_DENSITY = "support-any-density";
|
||||||
|
public static final String SUPPORTS_SCREENS = "support-screens";
|
||||||
|
public static final String TARGET_SDK_VERSION = "targetSdkVersion";
|
||||||
|
public static final String VERSION_CODE = "versionCode";
|
||||||
|
public static final String VERSION_NAME = "versionName";
|
||||||
|
public static final String USES_FEATURE = "uses-feature";
|
||||||
|
public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";
|
||||||
|
public static final String USES_PERMISSION = "uses-permission";
|
||||||
|
|
||||||
|
private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";
|
||||||
|
|
||||||
|
private ProcessBuilder builder;
|
||||||
|
// aapt 所在目录
|
||||||
|
private String aaptToolPath = "aapt";
|
||||||
|
|
||||||
|
public ApkUtil() {
|
||||||
|
builder = new ProcessBuilder();
|
||||||
|
builder.redirectErrorStream(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAaptToolPath() {
|
||||||
|
return aaptToolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAaptToolPath(String aaptToolPath) {
|
||||||
|
this.aaptToolPath = aaptToolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApkInfo parseApk(String apkPath) {
|
||||||
|
String aaptTool = aaptToolPath;
|
||||||
|
Process process = null;
|
||||||
|
InputStream inputStream = null;
|
||||||
|
BufferedReader bufferedReader = null;
|
||||||
|
try {
|
||||||
|
process = builder.command(aaptTool, "d", "badging", apkPath).start();
|
||||||
|
inputStream = process.getInputStream();
|
||||||
|
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
|
||||||
|
ApkInfo apkInfo = new ApkInfo();
|
||||||
|
apkInfo.setSize(new File(apkPath).length());
|
||||||
|
String temp = null;
|
||||||
|
while ((temp = bufferedReader.readLine()) != null) {
|
||||||
|
setApkInfoProperty(apkInfo, temp);
|
||||||
|
}
|
||||||
|
if (T.StrUtil.isBlank(apkInfo.getPackageName()) || T.StrUtil.isBlank(apkInfo.getVersionName())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return apkInfo;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e, "[parseApk] [error] [path: {}]", apkPath);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (process != null) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
T.IoUtil.close(inputStream);
|
||||||
|
T.IoUtil.close(bufferedReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApkInfo parseXapk(String xapkPath) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
File tempFile = null;
|
||||||
|
try {
|
||||||
|
ZipFile zipFile = new ZipFile(T.FileUtil.file(xapkPath));
|
||||||
|
ZipEntry entry = zipFile.getEntry("manifest.json");
|
||||||
|
inputStream = zipFile.getInputStream(entry);
|
||||||
|
StringBuilder manifestJson = new StringBuilder();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
manifestJson.append(line).append("\n");
|
||||||
|
}
|
||||||
|
Map manifest = T.JSONUtil.toBean(manifestJson.toString(), Map.class);
|
||||||
|
ZipEntry packageFile = zipFile.getEntry(T.StrUtil.concat(true, T.MapUtil.getStr(manifest, "package_name"), ".apk"));
|
||||||
|
tempFile = T.FileUtil.file(Constants.TEMP_PATH, packageFile.getName());
|
||||||
|
FileUtil.writeBytes(zipFile.getInputStream(packageFile).readAllBytes(), tempFile);
|
||||||
|
ApkInfo apkInfo = this.parseApk(tempFile.getPath());
|
||||||
|
if (apkInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!T.BooleanUtil.and(apkInfo.getVersionName().equals(T.MapUtil.getStr(manifest, "version_name")),
|
||||||
|
apkInfo.getPackageName().equals(T.MapUtil.getStr(manifest, "package_name")))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return apkInfo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[parseXapk] [error] [path: {}]", xapkPath);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
T.FileUtil.del(tempFile);
|
||||||
|
T.IoUtil.close(inputStream);
|
||||||
|
T.IoUtil.close(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setApkInfoProperty(ApkInfo apkInfo, String source) {
|
||||||
|
if (source.startsWith(APPLICATION)) {
|
||||||
|
String[] rs = source.split("( icon=')|'");
|
||||||
|
apkInfo.setIcon(rs[rs.length - 1]);
|
||||||
|
} else if (source.startsWith(APPLICATION_ICON)) {
|
||||||
|
apkInfo.addToIcons(getKeyBeforeColon(source), getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(APPLICATION_LABEL)) {
|
||||||
|
apkInfo.setLabel(getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(LAUNCHABLE_ACTIVITY)) {
|
||||||
|
apkInfo.setLaunchableActivity(getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(PACKAGE)) {
|
||||||
|
String[] packageInfo = source.split(SPLIT_REGEX);
|
||||||
|
apkInfo.setPackageName(packageInfo[2]);
|
||||||
|
apkInfo.setVersionCode(packageInfo[4]);
|
||||||
|
apkInfo.setVersionName(packageInfo[6]);
|
||||||
|
} else if (source.startsWith(SDK_VERSION)) {
|
||||||
|
apkInfo.setSdkVersion(getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(TARGET_SDK_VERSION)) {
|
||||||
|
apkInfo.setTargetSdkVersion(getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(USES_PERMISSION)) {
|
||||||
|
apkInfo.addToUsesPermissions(getPropertyInQuote(source));
|
||||||
|
} else if (source.startsWith(USES_FEATURE)) {
|
||||||
|
apkInfo.addToFeatures(getPropertyInQuote(source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getKeyBeforeColon(String source) {
|
||||||
|
return source.substring(0, source.indexOf(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPropertyInQuote(String source) {
|
||||||
|
int index = source.indexOf("'") + 1;
|
||||||
|
return source.substring(index, source.indexOf('\'', index));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package net.geedge.asw.module.app.util;
|
||||||
|
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class PkgConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android packages file dir
|
||||||
|
*/
|
||||||
|
public static File APK_FILES_DIR = T.FileUtil.file(T.WebPathUtil.getRootPath(), "apk_files");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* support platform
|
||||||
|
*/
|
||||||
|
public enum Platform {
|
||||||
|
ANDROID("android"),
|
||||||
|
|
||||||
|
IOS("ios"),
|
||||||
|
|
||||||
|
WINDOWS("windows"),
|
||||||
|
|
||||||
|
LINUX("linux");
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
Platform(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package net.geedge.asw.module.attribute.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import net.geedge.asw.common.util.R;
|
||||||
|
import net.geedge.asw.module.attribute.service.IAttributeService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/attribute")
|
||||||
|
public class AttributeController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAttributeService attributeService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public R list(@RequestParam Map<String, Object> params) {
|
||||||
|
Page page = attributeService.queryList(params);
|
||||||
|
return R.ok(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.geedge.asw.module.attribute.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.attribute.entity.AttributeEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface AttributeDao extends BaseMapper<AttributeEntity> {
|
||||||
|
|
||||||
|
List<AttributeEntity> queryList(@Param("params") Map<String, Object> params);
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package net.geedge.asw.module.attribute.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("attribute_dict")
|
||||||
|
public class AttributeEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String protocol;
|
||||||
|
|
||||||
|
private String layer;
|
||||||
|
|
||||||
|
private String stage;
|
||||||
|
|
||||||
|
private String objectType;
|
||||||
|
|
||||||
|
private Long createTimestamp;
|
||||||
|
|
||||||
|
private Long updateTimestamp;
|
||||||
|
|
||||||
|
private String createUserId;
|
||||||
|
|
||||||
|
private String updateUserId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.geedge.asw.module.attribute.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.attribute.entity.AttributeEntity;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface IAttributeService extends IService<AttributeEntity> {
|
||||||
|
Page queryList(Map<String, Object> params);
|
||||||
|
|
||||||
|
AttributeEntity queryAttribute(String type, String name);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package net.geedge.asw.module.attribute.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.attribute.dao.AttributeDao;
|
||||||
|
import net.geedge.asw.module.attribute.entity.AttributeEntity;
|
||||||
|
import net.geedge.asw.module.attribute.service.IAttributeService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AttributeServiceImpl extends ServiceImpl<AttributeDao, AttributeEntity> implements IAttributeService {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page queryList(Map<String, Object> params) {
|
||||||
|
|
||||||
|
Page page = T.PageUtil.getPage(params);
|
||||||
|
List<AttributeEntity> attributeList = this.getBaseMapper().queryList(params);
|
||||||
|
page.setRecords(attributeList);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttributeEntity queryAttribute(String type, String name) {
|
||||||
|
AttributeEntity one = this.getOne(new LambdaQueryWrapper<AttributeEntity>()
|
||||||
|
.eq(AttributeEntity::getType, type)
|
||||||
|
.eq(AttributeEntity::getName, name)
|
||||||
|
.last("limit 1")
|
||||||
|
);
|
||||||
|
return one;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
package net.geedge.asw.module.environment.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.geedge.asw.common.util.*;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import net.geedge.asw.module.environment.util.EnvironmentUtil;
|
||||||
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
|
import net.geedge.asw.module.runner.util.RunnerConstant;
|
||||||
|
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/env")
|
||||||
|
public class EnvironmentController {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysUserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPcapService pcapService;
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R detail(@PathVariable("id") String id) {
|
||||||
|
EnvironmentEntity entity = environmentService.queryInfo(id);
|
||||||
|
return R.ok().putData("record", entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public R list(@RequestParam Map<String, Object> params) {
|
||||||
|
T.VerifyUtil.is(params).notNull()
|
||||||
|
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
Page page = environmentService.queryList(params);
|
||||||
|
return R.ok(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/mgt")
|
||||||
|
public R queryList(@RequestParam Map<String, Object> params) {
|
||||||
|
Page page = environmentService.findEnvironmentByCurrentUserId(params);
|
||||||
|
return R.ok().putData(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/mgt")
|
||||||
|
public R save(@RequestBody EnvironmentEntity entity) {
|
||||||
|
EnvironmentEntity env = environmentService.saveEnv(entity);
|
||||||
|
return R.ok().putData("record", env.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/mgt")
|
||||||
|
public R update(@RequestBody EnvironmentEntity entity) {
|
||||||
|
EnvironmentEntity env = environmentService.updateEnv(entity);
|
||||||
|
return R.ok().putData("record", env.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/mgt")
|
||||||
|
public R delete(String ids) {
|
||||||
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
|
environmentService.removeEnv(T.ListUtil.of(ids.split(",")));
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/test")
|
||||||
|
public R testConnect(@RequestBody EnvironmentEntity entity) {
|
||||||
|
T.VerifyUtil.is(entity).notNull()
|
||||||
|
.and(entity.getParam()).notEmpty(RCode.PARAM_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
JSONObject jsonObject = entity.getParamJSONObject();
|
||||||
|
String url = jsonObject.getStr("url");
|
||||||
|
String token = jsonObject.getStr("token");
|
||||||
|
if (T.StrUtil.hasEmpty(url, token)) {
|
||||||
|
return R.error(RCode.PARAM_CANNOT_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpRequest request = T.HttpUtil.createGet(String.format("%s/api/v1/env/status", url));
|
||||||
|
request.header("Authorization", token);
|
||||||
|
HttpResponse response = request.execute();
|
||||||
|
log.info("[testConnect] [status: {}]", response.getStatus());
|
||||||
|
if (response.getStatus() == 401) {
|
||||||
|
return R.error(401, "Unauthorized");
|
||||||
|
}
|
||||||
|
if (response.isOk()) {
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e);
|
||||||
|
return R.error(RCode.ERROR);
|
||||||
|
}
|
||||||
|
return R.error(RCode.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/{envId}/session/{sessionId}/**", method ={ RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE}, headers = "Upgrade!=websocket")
|
||||||
|
public void agentEvn(@PathVariable("envId") String envId, @PathVariable("sessionId") String sessionId, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
EnvironmentSessionEntity session = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (T.ObjectUtil.isNull(session)){
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_SESSION_NOT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvironmentEntity environment = environmentService.getById(session.getEnvId());
|
||||||
|
if (T.ObjectUtil.isNull(environment)) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_NOT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvironmentUtil.getForObject(environment, request, response, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/mySession")
|
||||||
|
public R mySession(@RequestParam Map params){
|
||||||
|
Page page = environmentService.mySession(params);
|
||||||
|
return R.ok(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{envId}/session")
|
||||||
|
public R saveSession(@PathVariable("envId") String envId, @RequestParam String workspaceId){
|
||||||
|
EnvironmentSessionEntity session = environmentSessionService.saveSession(envId, workspaceId);
|
||||||
|
return R.ok().putData("record", session.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{envId}/session/{sessionId}")
|
||||||
|
public R querySession(@PathVariable("envId") String envId, @PathVariable("sessionId") String sessionId, @RequestParam String workspaceId){
|
||||||
|
EnvironmentSessionEntity session = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getWorkspaceId, workspaceId));
|
||||||
|
session.setEnv(environmentService.getById(envId));
|
||||||
|
session.setWorkspace(workspaceService.getById(workspaceId));
|
||||||
|
session.setUser(userService.getById(session.getUserId()));
|
||||||
|
return R.ok().putData("record", session);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@DeleteMapping("/{envId}/session/{sessionId}")
|
||||||
|
@Transactional
|
||||||
|
public R removeSession(@PathVariable("envId") String envId, @PathVariable("sessionId") String sessionId, @RequestParam String workspaceId) {
|
||||||
|
EnvironmentSessionEntity session = environmentSessionService.getById(sessionId);
|
||||||
|
WebSocketSession novncSession = Constants.ENV_NOVNC_WEBSOCKET_SESSION.get(sessionId);
|
||||||
|
WebSocketSession terminalSession = Constants.ENV_TERMINAL_WEBSOCKET_SESSION.get(sessionId);
|
||||||
|
// 根据 session 找到 novncSession&terminalSession ,更新状态,设置结束时间
|
||||||
|
session.setEndTimestamp(System.currentTimeMillis());
|
||||||
|
session.setStatus(2);
|
||||||
|
environmentSessionService.updateById(session);
|
||||||
|
try {
|
||||||
|
if (T.ObjectUtil.isNotEmpty(novncSession)) {
|
||||||
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
novncSession.close(CloseStatus.NORMAL.withReason("Administrator disconnected."));
|
||||||
|
}
|
||||||
|
if (T.ObjectUtil.isNotEmpty(terminalSession)) {
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
terminalSession.close(CloseStatus.NORMAL.withReason("Administrator disconnected."));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e, "RemoveSession send exit prompt error sessionId: {}", sessionId);
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@DeleteMapping("/{envId}/session/{sessionId}/pcap/{pcapId}")
|
||||||
|
public R stopTcpdump(@PathVariable("envId") String envId,
|
||||||
|
@PathVariable("sessionId") String sessionId,
|
||||||
|
@PathVariable("pcapId") String pcapId,
|
||||||
|
@RequestParam Map param) throws IOException, ServletException {
|
||||||
|
EnvironmentSessionEntity session = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (T.ObjectUtil.isNull(session)){
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_SESSION_NOT_EXIST);
|
||||||
|
}
|
||||||
|
EnvironmentEntity environment = environmentService.getById(envId);
|
||||||
|
if (T.ObjectUtil.isNull(environment)) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_NOT_EXIST);
|
||||||
|
}
|
||||||
|
// build query param
|
||||||
|
Map params = T.MapUtil.builder().put("id", pcapId).put("returnFile", T.MapUtil.getBool(param, "savePcap")).build();
|
||||||
|
ResponseEntity<byte[]> responseEntity = EnvironmentUtil.stopTcpdump(environment, params);
|
||||||
|
if (T.MapUtil.getBool(param, "savePcap")){
|
||||||
|
// save pcap to workspace
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(session.getWorkspaceId());
|
||||||
|
String pcapName = T.StrUtil.emptyToDefault(T.MapUtil.getStr(param,"pcapName"), pcapId);
|
||||||
|
File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), workspace.getId(), T.StrUtil.concat(true,pcapName, ".pcap"));
|
||||||
|
if (destination.exists()){
|
||||||
|
String formatTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
||||||
|
destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), workspace.getId(), T.StrUtil.concat(true, pcapName, "-", formatTime, ".pcap"));
|
||||||
|
}
|
||||||
|
// create empty file
|
||||||
|
destination = FileUtil.touch(destination);
|
||||||
|
if (ArrayUtil.isNotEmpty(responseEntity.getBody())){
|
||||||
|
FileOutputStream fos = new FileOutputStream(destination);
|
||||||
|
T.IoUtil.write(fos,true, responseEntity.getBody());
|
||||||
|
}
|
||||||
|
log.info("save pcap to path:{}", destination.getAbsolutePath());
|
||||||
|
// save entity
|
||||||
|
PcapEntity entity = new PcapEntity();
|
||||||
|
entity.setId(pcapId);
|
||||||
|
entity.setName(destination.getName());
|
||||||
|
entity.setSize(destination.length());
|
||||||
|
entity.setStatus(RunnerConstant.PcapStatus.UPLOADED.getValue());
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setWorkspaceId(workspace.getId());
|
||||||
|
entity.setPath(destination.getPath());
|
||||||
|
entity.setMd5(destination.length() == 0 ? Constants.EMPTY_FILE_MD5 : T.DigestUtil.md5Hex(destination));
|
||||||
|
pcapService.save(entity);
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.geedge.asw.module.environment.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface EnvironmentDao extends BaseMapper<EnvironmentEntity> {
|
||||||
|
|
||||||
|
List<EnvironmentEntity> queryList(Page page, Map<String, Object> params);
|
||||||
|
|
||||||
|
List<EnvironmentEntity> mySession(Page page, Map params);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package net.geedge.asw.module.environment.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface EnvironmentSessionDao extends BaseMapper<EnvironmentSessionEntity> {
|
||||||
|
|
||||||
|
List<EnvironmentSessionEntity> queryListByUsed();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.geedge.asw.module.environment.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentWorkspaceEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface EnvironmentWorkspaceDao extends BaseMapper<EnvironmentWorkspaceEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package net.geedge.asw.module.environment.entity;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("environment")
|
||||||
|
public class EnvironmentEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String location;
|
||||||
|
private String platform;
|
||||||
|
private Object param;
|
||||||
|
private String description;
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private Long lastHealthCheck;
|
||||||
|
private Long createTimestamp;
|
||||||
|
private Long updateTimestamp;
|
||||||
|
private String createUserId;
|
||||||
|
private String updateUserId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String workspaceId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private JSONObject useUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<WorkspaceEntity> workspaces;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private EnvironmentSessionEntity session;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<String> workspaceIds;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getParamStr() {
|
||||||
|
return null == this.param ? "{}" : T.JSONUtil.toJsonStr(this.param);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public JSONObject getParamJSONObject() {
|
||||||
|
return null == this.param ? new JSONObject() : T.JSONUtil.parseObj(this.getParamStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package net.geedge.asw.module.environment.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("environment_session")
|
||||||
|
public class EnvironmentSessionEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
private String envId;
|
||||||
|
private String userId;
|
||||||
|
private Integer status;
|
||||||
|
private String jobId;
|
||||||
|
|
||||||
|
private Long startTimestamp;
|
||||||
|
private Long endTimestamp;
|
||||||
|
|
||||||
|
private String workspaceId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private EnvironmentEntity env;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private WorkspaceEntity workspace;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity user;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package net.geedge.asw.module.environment.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("environment_workspace")
|
||||||
|
public class EnvironmentWorkspaceEntity {
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String envId;
|
||||||
|
private String workspaceId;
|
||||||
|
private Long createTimestamp;
|
||||||
|
private String createUserId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package net.geedge.asw.module.environment.job;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
import org.quartz.DisallowConcurrentExecution;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@DisallowConcurrentExecution
|
||||||
|
public class JobEnvironmentStatusChecker extends QuartzJobBean {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService envService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentSessionService envSessionService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
|
||||||
|
Thread.currentThread().setName("JobEnvironmentStatusChecker");
|
||||||
|
|
||||||
|
log.info("[JobEnvironmentStatusChecker] [begin]");
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
sw.start();
|
||||||
|
try {
|
||||||
|
this.environmentStatusChecker();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[JobEnvironmentStatusChecker] [error]");
|
||||||
|
} finally {
|
||||||
|
sw.stop();
|
||||||
|
}
|
||||||
|
log.info("[JobEnvironmentStatusChecker] [finshed] [Run Time: {}]", sw.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* environment status checker
|
||||||
|
* <p>
|
||||||
|
* 1. update entity status、lastHealthCheck
|
||||||
|
* 2. close the offline env session
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void environmentStatusChecker() {
|
||||||
|
List<EnvironmentEntity> list = envService.list();
|
||||||
|
for (EnvironmentEntity entity : list) {
|
||||||
|
Thread.ofVirtual().start(() -> {
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
JSONObject paramJSONObject = entity.getParamJSONObject();
|
||||||
|
String url = paramJSONObject.getStr("url");
|
||||||
|
String token = paramJSONObject.getStr("token");
|
||||||
|
|
||||||
|
HttpRequest request = T.HttpUtil.createGet(String.format("%s/api/v1/env/status", url));
|
||||||
|
request.header("Authorization", token);
|
||||||
|
|
||||||
|
HttpResponse response = request.execute();
|
||||||
|
log.info("[environmentStatusChecker] [env: {}] [status: {}]", entity.getId(), response.getStatus());
|
||||||
|
|
||||||
|
if (response.isOk()) {
|
||||||
|
result = response.body();
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log.error(e, "[environmentStatusChecker] [request api error] [env: {}]", entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[environmentStatusChecker] [env: {}] [result: {}]", entity.getId(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setStatus(0);
|
||||||
|
entity.setLastHealthCheck(System.currentTimeMillis());
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(result)) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(result);
|
||||||
|
if (T.ObjectUtil.equal(RCode.SUCCESS.getCode(), jsonObject.getInt("code"))) {
|
||||||
|
JSONObject data = jsonObject.getJSONObject("data");
|
||||||
|
String status = data.getStr("status");
|
||||||
|
if (T.StrUtil.equals("online", status)) {
|
||||||
|
entity.setStatus(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[environmentStatusChecker] [parse result error] [env: {}]", entity.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update entity status、lastHealthCheck
|
||||||
|
envService.update(new LambdaUpdateWrapper<EnvironmentEntity>()
|
||||||
|
.set(EnvironmentEntity::getStatus, entity.getStatus())
|
||||||
|
.set(EnvironmentEntity::getLastHealthCheck, entity.getLastHealthCheck())
|
||||||
|
.eq(EnvironmentEntity::getId, entity.getId())
|
||||||
|
);
|
||||||
|
|
||||||
|
// close the offline env session
|
||||||
|
if (0 == entity.getStatus()) {
|
||||||
|
envSessionService.update(new LambdaUpdateWrapper<EnvironmentSessionEntity>()
|
||||||
|
.set(EnvironmentSessionEntity::getStatus, 2)
|
||||||
|
.set(EnvironmentSessionEntity::getEndTimestamp, System.currentTimeMillis())
|
||||||
|
.eq(EnvironmentSessionEntity::getStatus, 1)
|
||||||
|
.eq(EnvironmentSessionEntity::getEnvId, entity.getId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.geedge.asw.module.environment.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface IEnvironmentService extends IService<EnvironmentEntity>{
|
||||||
|
|
||||||
|
EnvironmentEntity queryInfo(String id);
|
||||||
|
|
||||||
|
Page queryList(Map<String, Object> params);
|
||||||
|
|
||||||
|
Page findEnvironmentByCurrentUserId(Map<String, Object> params);
|
||||||
|
|
||||||
|
void removeEnv(List<String> ids);
|
||||||
|
|
||||||
|
Page mySession(Map params);
|
||||||
|
|
||||||
|
EnvironmentEntity saveEnv(EnvironmentEntity entity);
|
||||||
|
|
||||||
|
EnvironmentEntity updateEnv(EnvironmentEntity entity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.geedge.asw.module.environment.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IEnvironmentSessionService extends IService<EnvironmentSessionEntity>{
|
||||||
|
|
||||||
|
EnvironmentSessionEntity saveSession(String envId, String workspaceId);
|
||||||
|
|
||||||
|
List<EnvironmentSessionEntity> queryListByUsed();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package net.geedge.asw.module.environment.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentWorkspaceEntity;
|
||||||
|
|
||||||
|
public interface IEnvironmentWorkspaceService extends IService<EnvironmentWorkspaceEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
package net.geedge.asw.module.environment.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.config.Query;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.dao.EnvironmentDao;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentWorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentWorkspaceService;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EnvironmentServiceImpl extends ServiceImpl<EnvironmentDao, EnvironmentEntity> implements IEnvironmentService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysUserService sysUserService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentWorkspaceService environmentWorkspaceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnvironmentEntity queryInfo(String id) {
|
||||||
|
EnvironmentEntity environment = this.getById(id);
|
||||||
|
T.VerifyUtil.is(environment).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
// param
|
||||||
|
environment.setParam(environment.getParamJSONObject());
|
||||||
|
|
||||||
|
// user
|
||||||
|
SysUserEntity createUser = sysUserService.getById(environment.getCreateUserId());
|
||||||
|
SysUserEntity updateUser = sysUserService.getById(environment.getUpdateUserId());
|
||||||
|
createUser.setPwd(null);
|
||||||
|
updateUser.setPwd(null);
|
||||||
|
environment.setCreateUser(createUser);
|
||||||
|
environment.setUpdateUser(updateUser);
|
||||||
|
|
||||||
|
// workspaces
|
||||||
|
List<EnvironmentWorkspaceEntity> environmentWorkspaceList = environmentWorkspaceService.list(new LambdaQueryWrapper<EnvironmentWorkspaceEntity>().eq(EnvironmentWorkspaceEntity::getEnvId, id));
|
||||||
|
if (T.CollUtil.isNotEmpty(environmentWorkspaceList)) {
|
||||||
|
List<String> workspaceIds = environmentWorkspaceList.stream().map(x -> x.getWorkspaceId()).toList();
|
||||||
|
List<WorkspaceEntity> workspaceList = workspaceService.list(new LambdaQueryWrapper<WorkspaceEntity>().in(WorkspaceEntity::getId, workspaceIds));
|
||||||
|
environment.setWorkspaces(workspaceList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// session
|
||||||
|
EnvironmentSessionEntity deviceSession = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>()
|
||||||
|
.eq(EnvironmentSessionEntity::getEnvId, environment.getId())
|
||||||
|
.eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (null != deviceSession) {
|
||||||
|
SysUserEntity useUser = sysUserService.getById(deviceSession.getUserId());
|
||||||
|
useUser.setPwd(null);
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(deviceSession.getWorkspaceId());
|
||||||
|
deviceSession.setUser(useUser);
|
||||||
|
deviceSession.setWorkspace(workspace);
|
||||||
|
environment.setSession(deviceSession);
|
||||||
|
environment.setStatus(environment.getStatus() == 1 ? 2 : environment.getStatus());
|
||||||
|
}
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page queryList(Map<String, Object> params) {
|
||||||
|
Page page = T.PageUtil.getPage(params);
|
||||||
|
List<EnvironmentEntity> packageList = this.getBaseMapper().queryList(page, params);
|
||||||
|
|
||||||
|
List<EnvironmentSessionEntity> sessionEntityList = environmentSessionService.queryListByUsed();
|
||||||
|
List<String> envIdList = sessionEntityList.stream().map(x -> x.getEnvId()).toList();
|
||||||
|
|
||||||
|
Map<String, EnvironmentSessionEntity> sessionByEnvId = sessionEntityList.stream().collect(Collectors.toMap(EnvironmentSessionEntity::getEnvId, Function.identity()));
|
||||||
|
|
||||||
|
for (EnvironmentEntity entity : packageList) {
|
||||||
|
entity.setParam(entity.getParamJSONObject());
|
||||||
|
entity.setStatus(envIdList.contains(entity.getId()) ? 2 : entity.getStatus());
|
||||||
|
entity.setSession(sessionByEnvId.get(entity.getId()));
|
||||||
|
}
|
||||||
|
page.setRecords(packageList);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page findEnvironmentByCurrentUserId(Map<String, Object> params) {
|
||||||
|
params.put("currentUserId", StpUtil.getLoginIdAsString());
|
||||||
|
Page page = this.queryList(params);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void removeEnv(List<String> ids) {
|
||||||
|
// remove
|
||||||
|
this.remove(new LambdaQueryWrapper<EnvironmentEntity>().in(EnvironmentEntity::getId, ids).eq(EnvironmentEntity::getCreateUserId, StpUtil.getLoginIdAsString()));
|
||||||
|
|
||||||
|
// session
|
||||||
|
environmentSessionService.remove(new LambdaQueryWrapper<EnvironmentSessionEntity>().in(EnvironmentSessionEntity::getEnvId, ids));
|
||||||
|
|
||||||
|
//device workspace
|
||||||
|
environmentWorkspaceService.remove(new LambdaQueryWrapper<EnvironmentWorkspaceEntity>().in(EnvironmentWorkspaceEntity::getEnvId, ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page mySession(Map params) {
|
||||||
|
String currentUserId = StpUtil.getLoginIdAsString();
|
||||||
|
params.put("currentUserId", currentUserId);
|
||||||
|
Page page = new Query(EnvironmentEntity.class).getPage(params);
|
||||||
|
|
||||||
|
List<EnvironmentSessionEntity> sessionEntityList = environmentSessionService.queryListByUsed();
|
||||||
|
List<EnvironmentEntity> packageList = this.getBaseMapper().mySession(page, params);
|
||||||
|
List<String> envIdList = sessionEntityList.stream().map(x -> x.getEnvId()).toList();
|
||||||
|
Map<String, EnvironmentSessionEntity> sessionByEnvId = sessionEntityList.stream().collect(Collectors.toMap(EnvironmentSessionEntity::getEnvId, Function.identity()));
|
||||||
|
for (EnvironmentEntity entity : packageList) {
|
||||||
|
entity.setParam(entity.getParamJSONObject());
|
||||||
|
entity.setStatus(envIdList.contains(entity.getId()) ? 2 : entity.getStatus());
|
||||||
|
entity.setSession(sessionByEnvId.get(entity.getId()));
|
||||||
|
}
|
||||||
|
page.setRecords(packageList);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public EnvironmentEntity saveEnv(EnvironmentEntity entity) {
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setParam(entity.getParamStr());
|
||||||
|
this.save(entity);
|
||||||
|
|
||||||
|
// save env workspace
|
||||||
|
if (T.CollUtil.isNotEmpty(entity.getWorkspaceIds())){
|
||||||
|
List<EnvironmentWorkspaceEntity> list = T.ListUtil.list(false);
|
||||||
|
for (String workspaceId : entity.getWorkspaceIds()) {
|
||||||
|
EnvironmentWorkspaceEntity environmentWorkspace = new EnvironmentWorkspaceEntity();
|
||||||
|
environmentWorkspace.setEnvId(entity.getId());
|
||||||
|
environmentWorkspace.setWorkspaceId(workspaceId);
|
||||||
|
environmentWorkspace.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
environmentWorkspace.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
list.add(environmentWorkspace);
|
||||||
|
}
|
||||||
|
environmentWorkspaceService.saveBatch(list);
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public EnvironmentEntity updateEnv(EnvironmentEntity entity) {
|
||||||
|
|
||||||
|
EnvironmentEntity environment = this.getOne(new LambdaQueryWrapper<EnvironmentEntity>().eq(EnvironmentEntity::getId, entity.getId()).eq(EnvironmentEntity::getCreateUserId, StpUtil.getLoginIdAsString()));
|
||||||
|
if (T.ObjectUtil.isNull(environment)) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_NOT_EXIST);
|
||||||
|
}
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
entity.setParam(entity.getParamStr());
|
||||||
|
|
||||||
|
this.updateById(entity);
|
||||||
|
|
||||||
|
environmentWorkspaceService.remove(new LambdaQueryWrapper<EnvironmentWorkspaceEntity>().eq(EnvironmentWorkspaceEntity::getEnvId, entity.getId()));
|
||||||
|
// save env workspace
|
||||||
|
if (T.CollUtil.isNotEmpty(entity.getWorkspaceIds())){
|
||||||
|
List<EnvironmentWorkspaceEntity> list = T.ListUtil.list(false);
|
||||||
|
for (String workspaceId : entity.getWorkspaceIds()) {
|
||||||
|
EnvironmentWorkspaceEntity environmentWorkspace = new EnvironmentWorkspaceEntity();
|
||||||
|
environmentWorkspace.setEnvId(entity.getId());
|
||||||
|
environmentWorkspace.setWorkspaceId(workspaceId);
|
||||||
|
environmentWorkspace.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
environmentWorkspace.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
list.add(environmentWorkspace);
|
||||||
|
}
|
||||||
|
environmentWorkspaceService.saveBatch(list);
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package net.geedge.asw.module.environment.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.dao.EnvironmentSessionDao;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
import net.geedge.asw.module.environment.util.EnvironmentUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EnvironmentSessionServiceImpl extends ServiceImpl<EnvironmentSessionDao, EnvironmentSessionEntity> implements IEnvironmentSessionService {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnvironmentSessionEntity saveSession(String envId, String workspaceId) {
|
||||||
|
|
||||||
|
List<EnvironmentSessionEntity> sessionEntityList = this.list(new LambdaQueryWrapper<EnvironmentSessionEntity>()
|
||||||
|
.eq(EnvironmentSessionEntity::getEnvId, envId)
|
||||||
|
.eq(EnvironmentSessionEntity::getWorkspaceId, workspaceId)
|
||||||
|
.eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
|
||||||
|
if (T.CollectionUtil.isNotEmpty(sessionEntityList)) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_USED);
|
||||||
|
}
|
||||||
|
boolean isFree = this.checkEnvironmentStatus(envId);
|
||||||
|
if (!isFree) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
EnvironmentSessionEntity session = new EnvironmentSessionEntity();
|
||||||
|
session.setEnvId(envId);
|
||||||
|
session.setWorkspaceId(workspaceId);
|
||||||
|
session.setStatus(1);
|
||||||
|
session.setStartTimestamp(System.currentTimeMillis());
|
||||||
|
session.setUserId(StpUtil.getLoginIdAsString());
|
||||||
|
|
||||||
|
this.save(session);
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkEnvironmentStatus(String envId) {
|
||||||
|
boolean isFree = true;
|
||||||
|
EnvironmentEntity environment = environmentService.getById(envId);
|
||||||
|
if (T.ObjectUtil.isNull(environment)) {
|
||||||
|
throw new ASWException(RCode.ENVIRONMENT_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (environment.getStatus() != 1){
|
||||||
|
isFree = false;
|
||||||
|
}
|
||||||
|
String resultJsonStr = T.StrUtil.EMPTY_JSON;
|
||||||
|
try {
|
||||||
|
resultJsonStr = EnvironmentUtil.requestGet(environment, Constants.ENV_API_STATUS_PATH, null, String.class);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e, "CheckEnvironmentStatus. request environment status api error environment: {}]", T.JSONUtil.toJsonStr(environment));
|
||||||
|
isFree = false;
|
||||||
|
}
|
||||||
|
log.info("CheckEnvironmentStatus. environment status api result: {}", resultJsonStr);
|
||||||
|
|
||||||
|
Map resultObj = T.JSONUtil.toBean(resultJsonStr, Map.class);
|
||||||
|
if (T.BooleanUtil.or(
|
||||||
|
T.MapUtil.isEmpty(resultObj),
|
||||||
|
T.ObjectUtil.notEqual(RCode.SUCCESS.getCode(), resultObj.get("code")))) {
|
||||||
|
isFree = false;
|
||||||
|
} else {
|
||||||
|
Map data = T.MapUtil.get(resultObj, "data", Map.class);
|
||||||
|
String status = T.MapUtil.getStr(data, "status");
|
||||||
|
if (!T.StrUtil.equalsIgnoreCase(status, "online")){
|
||||||
|
isFree = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EnvironmentSessionEntity> queryListByUsed() {
|
||||||
|
List<EnvironmentSessionEntity> sessionEntityList = this.getBaseMapper().queryListByUsed();
|
||||||
|
return sessionEntityList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package net.geedge.asw.module.environment.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.module.environment.dao.EnvironmentWorkspaceDao;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentWorkspaceEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentWorkspaceService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EnvironmentWorkspaceServiceImpl extends ServiceImpl<EnvironmentWorkspaceDao, EnvironmentWorkspaceEntity> implements IEnvironmentWorkspaceService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
package net.geedge.asw.module.environment.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
|
import cn.hutool.core.net.url.UrlPath;
|
||||||
|
import cn.hutool.core.net.url.UrlQuery;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.http.Header;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.Part;
|
||||||
|
import net.geedge.asw.common.util.ASWException;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public class EnvironmentUtil {
|
||||||
|
|
||||||
|
private static Log log = Log.get();
|
||||||
|
private static RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public static <T> T requestGet(EnvironmentEntity environment, String path, String queryString, Class<T> responseType) {
|
||||||
|
return request(environment, HttpMethod.GET, path, queryString, null, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T request(EnvironmentEntity environment, HttpMethod method, String path, String queryString, Object body,
|
||||||
|
Class<T> responseType) {
|
||||||
|
JSONObject jsonObject = environment.getParamJSONObject();
|
||||||
|
String url = jsonObject.getStr("url");
|
||||||
|
String token = jsonObject.getStr("token");
|
||||||
|
|
||||||
|
String urlString = UrlBuilder.of(url)
|
||||||
|
.setPath(UrlPath.of(path, Charset.forName("UTF-8")))
|
||||||
|
.setQuery(UrlQuery.of(queryString, Charset.forName("UTF-8"), false, true))
|
||||||
|
.setCharset(StandardCharsets.UTF_8).toString();
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.AUTHORIZATION,token);
|
||||||
|
HttpEntity httpEntity = body == null ? new HttpEntity(headers) : new HttpEntity(body, headers);
|
||||||
|
// 发送 请求
|
||||||
|
return request(urlString, method, token, body, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T request(String url, HttpMethod method, String token, Object body, Class<T> responseType) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.AUTHORIZATION, token);
|
||||||
|
HttpEntity httpEntity = body == null ? new HttpEntity(headers) : new HttpEntity(body, headers);
|
||||||
|
// 发送 请求
|
||||||
|
ResponseEntity<T> exchange = null;
|
||||||
|
try {
|
||||||
|
exchange = restTemplate.exchange(new URI(url), method, httpEntity, responseType);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
log.error(e);
|
||||||
|
}
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T requestGet(String url, String token, Class<T> responseType) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.AUTHORIZATION, token);
|
||||||
|
HttpEntity httpEntity = new HttpEntity(headers);
|
||||||
|
// 发送 请求
|
||||||
|
ResponseEntity<T> exchange = restTemplate.exchange(url, HttpMethod.GET, httpEntity, responseType);
|
||||||
|
return exchange.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* agent stop tcpdump
|
||||||
|
* @param environment
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ServletException
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<byte[]> stopTcpdump(EnvironmentEntity environment, Map params) throws IOException, ServletException {
|
||||||
|
JSONObject jsonObject = environment.getParamJSONObject();
|
||||||
|
String url = jsonObject.getStr("url");
|
||||||
|
String token = jsonObject.getStr("token");
|
||||||
|
|
||||||
|
String urlStr = UrlBuilder.of(url)
|
||||||
|
.setPath(UrlPath.of(Constants.ENV_API_TCPDUMP_PATH, Charset.forName("UTF-8")))
|
||||||
|
.setQuery(UrlQuery.of(params))
|
||||||
|
.setCharset(StandardCharsets.UTF_8).toString();
|
||||||
|
// token
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.AUTHORIZATION, token);
|
||||||
|
HttpEntity httpEntity = new HttpEntity(headers);
|
||||||
|
ResponseEntity<byte[]> responseEntity = null;
|
||||||
|
try {
|
||||||
|
responseEntity = restTemplate.exchange(new URI(urlStr), HttpMethod.DELETE, httpEntity, byte[].class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "stop tcpdump request error. url:{}", urlStr);
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (ObjectUtil.isNotNull(e.getCause())) {
|
||||||
|
message = e.getCause().getMessage();
|
||||||
|
}
|
||||||
|
throw new ASWException(message, HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
}
|
||||||
|
int statusCode = responseEntity.getStatusCodeValue();
|
||||||
|
log.info("stop tcpdump request url:{}, responseStatus:{}", urlStr, statusCode);
|
||||||
|
return responseEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env api agent
|
||||||
|
* @param device
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param sessionId
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ServletException
|
||||||
|
*/
|
||||||
|
public static void getForObject(EnvironmentEntity device, HttpServletRequest request, HttpServletResponse response, String sessionId) throws IOException, ServletException {
|
||||||
|
// path
|
||||||
|
String[] paths = request.getServletPath().split(sessionId);
|
||||||
|
String path = Arrays.asList(paths).getLast();
|
||||||
|
path = path.startsWith("/") ? (String.format("%s%s", Constants.ENV_API_PREFIX, path))
|
||||||
|
: (String.format("%s/%s", Constants.ENV_API_PREFIX, path));
|
||||||
|
|
||||||
|
// host port token
|
||||||
|
JSONObject jsonObject = device.getParamJSONObject();
|
||||||
|
String url = jsonObject.getStr("url");
|
||||||
|
String token = jsonObject.getStr("token");
|
||||||
|
|
||||||
|
// query param
|
||||||
|
String queryString = request.getQueryString();
|
||||||
|
queryString = StrUtil.isNotBlank(queryString) ? queryString : "";
|
||||||
|
queryString = URLUtil.decode(queryString);
|
||||||
|
|
||||||
|
|
||||||
|
String urlStr = UrlBuilder.of(url)
|
||||||
|
.setPath(UrlPath.of(path, Charset.forName("UTF-8")))
|
||||||
|
.setQuery(UrlQuery.of(queryString, Charset.forName("UTF-8"), false, true))
|
||||||
|
.setCharset(StandardCharsets.UTF_8).toString();
|
||||||
|
|
||||||
|
// token
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
Enumeration<String> headerNames = request.getHeaderNames();
|
||||||
|
while (headerNames.hasMoreElements()) {
|
||||||
|
String hn = headerNames.nextElement();
|
||||||
|
if (Constants.AUTH_TOKEN_CODE.equalsIgnoreCase(hn)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
headers.add(hn, request.getHeader(hn));
|
||||||
|
}
|
||||||
|
headers.add(HttpHeaders.AUTHORIZATION, token);
|
||||||
|
|
||||||
|
// body
|
||||||
|
byte[] body = T.IoUtil.readBytes(request.getInputStream());
|
||||||
|
HttpEntity httpEntity = new HttpEntity(body, headers);
|
||||||
|
|
||||||
|
// from-data
|
||||||
|
if (request.getContentType() != null &&
|
||||||
|
request.getContentType().startsWith("multipart")) {
|
||||||
|
// 获取表单中的文件和参数
|
||||||
|
Collection<Part> parts = request.getParts();
|
||||||
|
// from 表单文件
|
||||||
|
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
|
||||||
|
for (Part part : parts) {
|
||||||
|
String partName = part.getName();
|
||||||
|
if (part.getSubmittedFileName() != null) {
|
||||||
|
ByteArrayResource resource = new ByteArrayResource(part.getInputStream().readAllBytes()) {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return part.getSubmittedFileName();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
form.add(partName, resource);
|
||||||
|
} else {
|
||||||
|
form.add(partName, part.getInputStream().readAllBytes());
|
||||||
|
}
|
||||||
|
httpEntity = new HttpEntity(form, headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> responseEntity = null;
|
||||||
|
try {
|
||||||
|
responseEntity = restTemplate.exchange(new URI(urlStr), HttpMethod.valueOf(request.getMethod()), httpEntity, byte[].class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "env request error. url:{}", urlStr);
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (ObjectUtil.isNotNull(e.getCause())) {
|
||||||
|
message = e.getCause().getMessage();
|
||||||
|
}
|
||||||
|
throw new ASWException(message, HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
}
|
||||||
|
log.info("env request url:{}, responseStatus:{}", urlStr, responseEntity.getStatusCode());
|
||||||
|
writeResponseWithHeaders(response, responseEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeResponseWithHeaders(HttpServletResponse response, ResponseEntity<byte[]> responseEntity) throws IOException {
|
||||||
|
HttpHeaders httpHeaders = responseEntity.getHeaders();
|
||||||
|
int statusCode = responseEntity.getStatusCodeValue();
|
||||||
|
byte[] responseBody = responseEntity.getBody();
|
||||||
|
response.reset();
|
||||||
|
response.setStatus(statusCode);
|
||||||
|
Set<Map.Entry<String, List<String>>> entrySet = httpHeaders.entrySet();
|
||||||
|
// 设置 cors 响应头
|
||||||
|
Constants.CORS_HEADER.forEach((k, v) -> {
|
||||||
|
response.setHeader(k, v);
|
||||||
|
});
|
||||||
|
for (Map.Entry<String, List<String>> en : entrySet) {
|
||||||
|
String name = en.getKey();
|
||||||
|
List<String> value = en.getValue();
|
||||||
|
if (en.getKey().equalsIgnoreCase(Header.CONTENT_LENGTH.getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (en.getKey().equalsIgnoreCase(Header.TRANSFER_ENCODING.getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
response.setHeader(name, T.StrUtil.join(",", value.toArray()));
|
||||||
|
}
|
||||||
|
response.setContentLength(T.ArrayUtil.length(responseBody));
|
||||||
|
response.getOutputStream().write(responseBody);
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setRestTemplate(RestTemplate restTemplate) {
|
||||||
|
EnvironmentUtil.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,10 +4,7 @@ import cn.hutool.core.net.url.UrlBuilder;
|
|||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import feign.Feign;
|
import feign.Feign;
|
||||||
import feign.form.FormEncoder;
|
import feign.form.FormEncoder;
|
||||||
import net.geedge.asw.module.feign.client.GeoipClient;
|
import net.geedge.asw.module.feign.client.*;
|
||||||
import net.geedge.asw.module.feign.client.KibanaClient;
|
|
||||||
import net.geedge.asw.module.feign.client.WebSharkClient;
|
|
||||||
import net.geedge.asw.module.feign.client.ZeekClient;
|
|
||||||
import net.geedge.asw.module.feign.support.Fastjson2Decoder;
|
import net.geedge.asw.module.feign.support.Fastjson2Decoder;
|
||||||
import net.geedge.asw.module.feign.support.Fastjson2Encoder;
|
import net.geedge.asw.module.feign.support.Fastjson2Encoder;
|
||||||
import net.geedge.asw.module.feign.support.Http2Client;
|
import net.geedge.asw.module.feign.support.Http2Client;
|
||||||
@@ -32,6 +29,9 @@ public class FeignClientConfiguration {
|
|||||||
@Value("${webShark.url:127.0.0.1:8085}")
|
@Value("${webShark.url:127.0.0.1:8085}")
|
||||||
private String websharkurl;
|
private String websharkurl;
|
||||||
|
|
||||||
|
@Value("${pcapComment.url:127.0.0.1:5000}")
|
||||||
|
private String pcapCommentUrl;
|
||||||
|
|
||||||
@Bean("zeekClient")
|
@Bean("zeekClient")
|
||||||
public ZeekClient zeekClient() {
|
public ZeekClient zeekClient() {
|
||||||
String url = UrlBuilder.ofHttp(zeekUrl).toString();
|
String url = UrlBuilder.ofHttp(zeekUrl).toString();
|
||||||
@@ -71,9 +71,29 @@ public class FeignClientConfiguration {
|
|||||||
log.info("[webSharkClient] [url: {}]", url);
|
log.info("[webSharkClient] [url: {}]", url);
|
||||||
return Feign.builder()
|
return Feign.builder()
|
||||||
.encoder(new FormEncoder())
|
.encoder(new FormEncoder())
|
||||||
.decoder(new Fastjson2Decoder())
|
|
||||||
.client(new Http2Client())
|
.client(new Http2Client())
|
||||||
.target(WebSharkClient.class, url);
|
.target(WebSharkClient.class, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean("pcapCommentClient")
|
||||||
|
public PcapCommentClient pcapCommentClient() {
|
||||||
|
String url = UrlBuilder.ofHttp(pcapCommentUrl).toString();
|
||||||
|
log.info("[pcapCommentClient] [url: {}]", url);
|
||||||
|
return Feign.builder()
|
||||||
|
.encoder(new FormEncoder())
|
||||||
|
.client(new Http2Client())
|
||||||
|
.target(PcapCommentClient.class, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("dashboardClient")
|
||||||
|
public DashboardClient dashboardClient() {
|
||||||
|
String url = UrlBuilder.ofHttp(kibanaUrl).toString();
|
||||||
|
log.info("[kibanaClient] [url: {}]", url);
|
||||||
|
return Feign.builder()
|
||||||
|
.encoder(new FormEncoder())
|
||||||
|
.decoder(new Fastjson2Decoder())
|
||||||
|
.client(new Http2Client())
|
||||||
|
.target(DashboardClient.class, url);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import feign.Headers;
|
||||||
|
import feign.Param;
|
||||||
|
import feign.RequestLine;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@FeignClient(name = "dashboardClient")
|
||||||
|
@Headers("Authorization: Bearer {token}")
|
||||||
|
public interface DashboardClient {
|
||||||
|
|
||||||
|
@Headers({
|
||||||
|
"Content-Type: multipart/form-data",
|
||||||
|
"osd-xsrf: true",
|
||||||
|
"kbn-xsrf: true"
|
||||||
|
})
|
||||||
|
@RequestLine("POST /api/saved_objects/_import?createNewCopies={createNewCopies}")
|
||||||
|
JSONObject importDashboard(@Param("token") String token, @Param("file") File file, @Param("createNewCopies") boolean createNewCopies);
|
||||||
|
}
|
||||||
@@ -10,8 +10,8 @@ import org.springframework.cloud.openfeign.FeignClient;
|
|||||||
@Headers("Authorization: Bearer {token}")
|
@Headers("Authorization: Bearer {token}")
|
||||||
public interface KibanaClient {
|
public interface KibanaClient {
|
||||||
|
|
||||||
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type=index-pattern&search_fields=title&search={name}")
|
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type={type}&search_fields=title&search={name}")
|
||||||
JSONObject findIndexPattern(@Param("token") String token, @Param("name") String name);
|
JSONObject findIndexPattern(@Param("token") String token, @Param("type") String type , @Param("name") String name);
|
||||||
|
|
||||||
@Headers({
|
@Headers({
|
||||||
"Content-Type: application/json",
|
"Content-Type: application/json",
|
||||||
@@ -20,4 +20,11 @@ public interface KibanaClient {
|
|||||||
@RequestLine("POST /api/saved_objects/index-pattern/{id}")
|
@RequestLine("POST /api/saved_objects/index-pattern/{id}")
|
||||||
JSONObject saveIndexPattern(@Param("token") String token, @Param("id") String id, JSONObject body);
|
JSONObject saveIndexPattern(@Param("token") String token, @Param("id") String id, JSONObject body);
|
||||||
|
|
||||||
|
@Headers({
|
||||||
|
"Content-Type: application/json",
|
||||||
|
"osd-xsrf: true"
|
||||||
|
})
|
||||||
|
@RequestLine("DELETE /api/saved_objects/index-pattern/{id}?force={force}")
|
||||||
|
JSONObject deleteIndexPattern(@Param("token") String token, @Param("id") String id , @Param("force") boolean force);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
|
import feign.Headers;
|
||||||
|
import feign.Param;
|
||||||
|
import feign.RequestLine;
|
||||||
|
import feign.Response;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@FeignClient(name = "pcapCommentClient")
|
||||||
|
public interface PcapCommentClient {
|
||||||
|
|
||||||
|
@RequestLine("POST /api/v1/pcap/comment")
|
||||||
|
@Headers("Content-Type: multipart/form-data")
|
||||||
|
Response addCommon(@Param("file") File file, @Param("url") String url, @Param("id") String pcapId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package net.geedge.asw.module.feign.client;
|
package net.geedge.asw.module.feign.client;
|
||||||
|
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import feign.Headers;
|
import feign.Headers;
|
||||||
import feign.Param;
|
import feign.Param;
|
||||||
import feign.RequestLine;
|
import feign.RequestLine;
|
||||||
|
import feign.Response;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -14,5 +14,5 @@ public interface WebSharkClient {
|
|||||||
|
|
||||||
@RequestLine("POST /webshark/upload")
|
@RequestLine("POST /webshark/upload")
|
||||||
@Headers("Content-Type: multipart/form-data")
|
@Headers("Content-Type: multipart/form-data")
|
||||||
JSONObject upload(@Param("fileKey") File file);
|
Response upload(@Param("fileKey") File file);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,55 +10,68 @@ import net.geedge.asw.module.runner.service.IJobService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/job")
|
@RequestMapping("/api/v1/workspace")
|
||||||
public class JobController {
|
public class JobController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IJobService jobService;
|
private IJobService jobService;
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{workspaceId}/job/{id}")
|
||||||
public R detail(@PathVariable("id") String id) {
|
public R detail(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@PathVariable("id") String id) {
|
||||||
JobEntity jobEntity = jobService.queryInfo(id);
|
JobEntity jobEntity = jobService.queryInfo(id);
|
||||||
return R.ok().putData("record", jobEntity);
|
return R.ok().putData("record", jobEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping("/{workspaceId}/job")
|
||||||
public R list(@RequestParam Map<String, Object> params) {
|
public R list(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam Map<String, Object> params) {
|
||||||
T.VerifyUtil.is(params).notNull()
|
T.VerifyUtil.is(params).notNull()
|
||||||
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
params.put("workspaceId", workspaceId);
|
||||||
Page page = jobService.queryList(params);
|
Page page = jobService.queryList(params);
|
||||||
return R.ok(page);
|
return R.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping("/{workspaceId}/job")
|
||||||
public R add(@RequestBody JobEntity entity) {
|
public R add(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestBody JobEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull()
|
T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getRunnerId()).notEmpty(RCode.RUNNER_ID_CANNOT_EMPTY)
|
.and(entity.getEnvironmentId()).notEmpty(RCode.ENVIRONMENT_ID_CANNOT_EMPTY)
|
||||||
.and(entity.getPackageId()).notEmpty(RCode.PACKAGE_ID_CANNOT_EMPTY)
|
.and(entity.getPackageId()).notEmpty(RCode.PACKAGE_ID_CANNOT_EMPTY)
|
||||||
|
.and(entity.getPlaybookId()).notEmpty(RCode.PLAYBOOK_ID_CANNOT_EMPTY)
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
entity.setEnvId(entity.getEnvironmentId());
|
||||||
|
|
||||||
JobEntity jobEntity = jobService.saveJob(entity);
|
JobEntity jobEntity = jobService.saveJob(entity);
|
||||||
return R.ok().putData("id", jobEntity.getId());
|
return R.ok().putData("id", jobEntity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping("/{workspaceId}/job")
|
||||||
public R delete(String[] ids) {
|
public R delete(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam String ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
jobService.removeJob(T.ListUtil.of(ids));
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
|
jobService.removeJob(idList);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/cancel")
|
@PutMapping("/{workspaceId}/job/cancel")
|
||||||
public R cancel(String[] ids) {
|
public R cancel(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam String ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
// TODO 其他处理
|
// TODO 其他处理
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
jobService.update(new LambdaUpdateWrapper<JobEntity>()
|
jobService.update(new LambdaUpdateWrapper<JobEntity>()
|
||||||
.in(JobEntity::getId, ids)
|
.in(JobEntity::getId, idList)
|
||||||
.set(JobEntity::getStatus, "cancel")
|
.set(JobEntity::getStatus, "cancel")
|
||||||
);
|
);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import cn.hutool.core.date.DatePattern;
|
|||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.net.url.UrlBuilder;
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import feign.Response;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.common.config.SpringContextUtils;
|
import net.geedge.asw.common.config.SpringContextUtils;
|
||||||
import net.geedge.asw.common.util.*;
|
import net.geedge.asw.common.util.*;
|
||||||
@@ -16,6 +17,7 @@ import net.geedge.asw.module.runner.entity.PcapEntity;
|
|||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -23,7 +25,11 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/pcap")
|
@RequestMapping("/api/v1/pcap")
|
||||||
@@ -56,7 +62,6 @@ public class PcapController {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R add(@RequestParam(value = "files", required = true) List<MultipartFile> fileList,
|
public R add(@RequestParam(value = "files", required = true) List<MultipartFile> fileList,
|
||||||
@RequestParam(value = "descriptions", required = false) List<String> descriptionList,
|
@RequestParam(value = "descriptions", required = false) List<String> descriptionList,
|
||||||
@RequestParam(required = false) String workbookId,
|
|
||||||
@RequestParam(required = false) String workspaceId) throws IOException {
|
@RequestParam(required = false) String workspaceId) throws IOException {
|
||||||
T.VerifyUtil.is(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
T.VerifyUtil.is(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
|
||||||
@@ -64,7 +69,7 @@ public class PcapController {
|
|||||||
for (int i = 0; i < fileList.size(); i++) {
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
MultipartFile file = fileList.get(i);
|
MultipartFile file = fileList.get(i);
|
||||||
String description = T.StrUtil.emptyToDefault(T.CollUtil.get(descriptionList, i), "");
|
String description = T.StrUtil.emptyToDefault(T.CollUtil.get(descriptionList, i), "");
|
||||||
PcapEntity pcapEntity = pcapService.savePcap(file.getResource(), description, workbookId, workspaceId);
|
PcapEntity pcapEntity = pcapService.savePcap(file.getResource(), description, workspaceId);
|
||||||
recordList.add(
|
recordList.add(
|
||||||
T.MapUtil.builder()
|
T.MapUtil.builder()
|
||||||
.put("id", pcapEntity.getId())
|
.put("id", pcapEntity.getId())
|
||||||
@@ -110,7 +115,19 @@ public class PcapController {
|
|||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
|
|
||||||
pcapService.parse2session(ids);
|
pcapService.parse2session(ids);
|
||||||
return R.ok();
|
|
||||||
|
// records
|
||||||
|
List<PcapEntity> entityList = pcapService.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, ids));
|
||||||
|
List<Map<String, String>> records = entityList.stream()
|
||||||
|
.map(entity ->
|
||||||
|
Map.of(
|
||||||
|
"id", entity.getId(),
|
||||||
|
"name", entity.getName(),
|
||||||
|
"status", entity.getStatus()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return R.ok().putData("records", records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,18 +156,20 @@ public class PcapController {
|
|||||||
|
|
||||||
HashMap<Object, Object> result = T.MapUtil.newHashMap();
|
HashMap<Object, Object> result = T.MapUtil.newHashMap();
|
||||||
PcapEntity pcap = pcapService.getById(id);
|
PcapEntity pcap = pcapService.getById(id);
|
||||||
File pcapFile = T.FileUtil.file(pcap.getPath());
|
File pcapFile = pcap.getCommonPcapFilePath().toFile();
|
||||||
|
pcapFile = FileUtil.exist(pcapFile) ? pcapFile : T.FileUtil.file(pcap.getPath());
|
||||||
String uploadFileName = T.StrUtil.concat(true, id, ".", T.FileUtil.getSuffix(pcapFile));
|
String uploadFileName = T.StrUtil.concat(true, id, ".", T.FileUtil.getSuffix(pcapFile));
|
||||||
File newFile = FileUtil.copy(pcapFile, FileUtil.file(Constants.TEMP_PATH, uploadFileName), false);
|
File newFile = FileUtil.copy(pcapFile, FileUtil.file(Constants.TEMP_PATH, uploadFileName), false);
|
||||||
try {
|
try {
|
||||||
WebSharkClient webSharkClient = (WebSharkClient) SpringContextUtils.getBean("webSharkClient");
|
WebSharkClient webSharkClient = (WebSharkClient) SpringContextUtils.getBean("webSharkClient");
|
||||||
JSONObject obj = webSharkClient.upload(newFile);
|
Response obj = webSharkClient.upload(newFile);
|
||||||
|
if (T.ObjectUtil.isNotEmpty(obj) && HttpStatus.resolve(obj.status()).is2xxSuccessful()){
|
||||||
String baseUrl = UrlBuilder.ofHttp(websharkurl)
|
String baseUrl = UrlBuilder.ofHttp(websharkurl)
|
||||||
.addPath("/webshark")
|
.addPath("/webshark")
|
||||||
.toString();
|
.toString();
|
||||||
result.put("fileName", uploadFileName);
|
result.put("fileName", uploadFileName);
|
||||||
result.put("url", baseUrl);
|
result.put("url", baseUrl);
|
||||||
|
}
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
log.error(e, "webshark upload pcap error, id: {}", pcap.getId());
|
log.error(e, "webshark upload pcap error, id: {}", pcap.getId());
|
||||||
throw new ASWException(RCode.PCAP_UPLOAD_WEB_SHARK_ERROR);
|
throw new ASWException(RCode.PCAP_UPLOAD_WEB_SHARK_ERROR);
|
||||||
@@ -168,4 +187,16 @@ public class PcapController {
|
|||||||
pcapService.unparse2session(ids);
|
pcapService.unparse2session(ids);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/explore")
|
||||||
|
public R explore(@RequestParam String workspaceId, @RequestParam String pcapIds, @RequestParam(required = false) String protocol, @RequestParam(required = false) String streamId) {
|
||||||
|
String discoverUrl = pcapService.generateKibanaDiscoverUrl(workspaceId, pcapIds, protocol, streamId);
|
||||||
|
return R.ok().putData("url", discoverUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/dashboard")
|
||||||
|
public R dashboard(@RequestParam String workspaceId, @RequestParam String pcapIds) {
|
||||||
|
String dashboardUrl = pcapService.generateKibanaDashboardUrl(workspaceId, pcapIds);
|
||||||
|
return R.ok().putData("url", dashboardUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package net.geedge.asw.module.runner.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import net.geedge.asw.common.util.R;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.ResponseUtil;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
|
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/workspace")
|
||||||
|
public class PlaybookController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPlaybookService playbookService;
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/playbook/{id}")
|
||||||
|
public R detail(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) {
|
||||||
|
PlaybookEntity playbook = playbookService.detail(workspaceId, id);
|
||||||
|
return R.ok().put("record", playbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/playbook")
|
||||||
|
public R list(@PathVariable("workspaceId") String workspaceId, @RequestParam Map params) {
|
||||||
|
Page page = playbookService.queryList(workspaceId, params);
|
||||||
|
return R.ok(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{workspaceId}/playbook")
|
||||||
|
public R save(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam("file") MultipartFile file,
|
||||||
|
@RequestParam("name") String name,
|
||||||
|
@RequestParam(value = "description", required = false) String description) {
|
||||||
|
PlaybookEntity playbook = playbookService.savePlaybook(workspaceId, file, name, description);
|
||||||
|
return R.ok().put("record", playbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{workspaceId}/playbook")
|
||||||
|
public R delete(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@RequestParam("ids") String ids) {
|
||||||
|
playbookService.delete(workspaceId, ids);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/playbook/{id}/download")
|
||||||
|
public void download(@PathVariable("workspaceId") String workspaceId,
|
||||||
|
@PathVariable("id") String id, HttpServletResponse response) throws IOException {
|
||||||
|
|
||||||
|
PlaybookEntity entity = playbookService.getById(id);
|
||||||
|
T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
File playbookFile = T.FileUtil.file(entity.getPath());
|
||||||
|
ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, entity.getName(), T.FileUtil.readBytes(playbookFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,174 +1,174 @@
|
|||||||
package net.geedge.asw.module.runner.controller;
|
//package net.geedge.asw.module.runner.controller;
|
||||||
|
//
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
//import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
import cn.hutool.core.lang.Opt;
|
//import cn.hutool.core.lang.Opt;
|
||||||
import cn.hutool.log.Log;
|
//import cn.hutool.log.Log;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
//import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
//import jakarta.servlet.http.HttpServletResponse;
|
||||||
import net.geedge.asw.common.util.R;
|
//import net.geedge.asw.common.util.R;
|
||||||
import net.geedge.asw.common.util.RCode;
|
//import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
//import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
//import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
//import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
//import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
//import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||||
import net.geedge.asw.module.runner.service.IJobService;
|
//import net.geedge.asw.module.runner.service.IJobService;
|
||||||
import net.geedge.asw.module.runner.service.IRunnerService;
|
//import net.geedge.asw.module.runner.service.IRunnerService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
//import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
//import org.springframework.web.multipart.MultipartFile;
|
||||||
|
//
|
||||||
import java.io.IOException;
|
//import java.io.IOException;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
@RestController
|
//@RestController
|
||||||
@RequestMapping("/api/v1/runner")
|
//@RequestMapping("/api/v1/runner")
|
||||||
public class RunnerController {
|
//public class RunnerController {
|
||||||
|
//
|
||||||
private static final Log log = Log.get();
|
// private static final Log log = Log.get();
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private IJobService jobService;
|
// private IJobService jobService;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private IRunnerService runnerService;
|
// private IRunnerService runnerService;
|
||||||
|
//
|
||||||
@GetMapping("/{id}")
|
// @GetMapping("/{id}")
|
||||||
public R detail(@PathVariable("id") String id) {
|
// public R detail(@PathVariable("id") String id) {
|
||||||
RunnerEntity runnerEntity = runnerService.getById(id);
|
// RunnerEntity runnerEntity = runnerService.getById(id);
|
||||||
return R.ok().putData("record", runnerEntity);
|
// return R.ok().putData("record", runnerEntity);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@GetMapping
|
// @GetMapping
|
||||||
public R list(@RequestParam Map<String, Object> params) {
|
// public R list(@RequestParam Map<String, Object> params) {
|
||||||
T.VerifyUtil.is(params).notNull()
|
// T.VerifyUtil.is(params).notNull()
|
||||||
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
// .and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
//
|
||||||
Page page = runnerService.queryList(params);
|
// Page page = runnerService.queryList(params);
|
||||||
return R.ok(page);
|
// return R.ok(page);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@PostMapping
|
// @PostMapping
|
||||||
public R add(@RequestBody RunnerEntity entity) {
|
// public R add(@RequestBody RunnerEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull()
|
// T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
// .and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
//
|
||||||
RunnerEntity runner = runnerService.saveRunner(entity);
|
// RunnerEntity runner = runnerService.saveRunner(entity);
|
||||||
return R.ok().putData("record", runner);
|
// return R.ok().putData("record", runner);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@PutMapping
|
// @PutMapping
|
||||||
public R update(@RequestBody RunnerEntity entity) {
|
// public R update(@RequestBody RunnerEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull()
|
// T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
// .and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
// .and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||||
|
//
|
||||||
RunnerEntity runner = runnerService.updateRunner(entity);
|
// RunnerEntity runner = runnerService.updateRunner(entity);
|
||||||
return R.ok().putData("record", runner);
|
// return R.ok().putData("record", runner);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@DeleteMapping("/{id}")
|
// @DeleteMapping("/{id}")
|
||||||
public R delete(@PathVariable("id") String id) {
|
// public R delete(@PathVariable("id") String id) {
|
||||||
runnerService.removeById(id);
|
// runnerService.removeById(id);
|
||||||
return R.ok();
|
// return R.ok();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@SaIgnore
|
// @SaIgnore
|
||||||
@PostMapping("/register")
|
// @PostMapping("/register")
|
||||||
public void register(@RequestHeader("Authorization") String token, HttpServletResponse response) throws IOException {
|
// public void register(@RequestHeader("Authorization") String token, HttpServletResponse response) throws IOException {
|
||||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
// RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
// String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||||
if (!T.StrUtil.equals("online", status)) {
|
// if (!T.StrUtil.equals("online", status)) {
|
||||||
log.warn("[register] [runner is offline] [token: {}]", token);
|
// log.warn("[register] [runner is offline] [token: {}]", token);
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@SaIgnore
|
// @SaIgnore
|
||||||
@PostMapping("/heartbeat")
|
// @PostMapping("/heartbeat")
|
||||||
public void heartbeat(@RequestHeader("Authorization") String token, @RequestBody Map<String, Integer> platformMap,
|
// public void heartbeat(@RequestHeader("Authorization") String token, @RequestBody Map<String, Integer> platformMap,
|
||||||
HttpServletResponse response) throws IOException {
|
// HttpServletResponse response) throws IOException {
|
||||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
// RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
// String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||||
if (!T.StrUtil.equals("online", status)) {
|
// if (!T.StrUtil.equals("online", status)) {
|
||||||
log.warn("[heartbeat] [runner is offline] [token: {}]", token);
|
// log.warn("[heartbeat] [runner is offline] [token: {}]", token);
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// update last_heartbeat_timestamp
|
// // update last_heartbeat_timestamp
|
||||||
runnerService.update(new LambdaUpdateWrapper<RunnerEntity>()
|
// runnerService.update(new LambdaUpdateWrapper<RunnerEntity>()
|
||||||
.set(RunnerEntity::getLastHeartbeatTimestamp, System.currentTimeMillis())
|
// .set(RunnerEntity::getLastHeartbeatTimestamp, System.currentTimeMillis())
|
||||||
.eq(RunnerEntity::getId, runner.getId()));
|
// .eq(RunnerEntity::getId, runner.getId()));
|
||||||
|
//
|
||||||
// findjob by platform
|
// // findjob by platform
|
||||||
String platform = platformMap.entrySet().stream().filter(entry -> entry.getValue() > 0).findFirst().map(entry -> entry.getKey()).orElseGet(null);
|
// String platform = platformMap.entrySet().stream().filter(entry -> entry.getValue() > 0).findFirst().map(entry -> entry.getKey()).orElseGet(null);
|
||||||
JobEntity job = jobService.assignPendingJob(runner.getId(), platform);
|
// JobEntity job = jobService.assignPendingJob(runner.getId(), platform);
|
||||||
if (T.ObjectUtil.isNotNull(job)) {
|
// if (T.ObjectUtil.isNotNull(job)) {
|
||||||
// package
|
// // package
|
||||||
PackageEntity pkg = job.getPkg();
|
// PackageEntity pkg = job.getPkg();
|
||||||
Map<String, String> pkgInfo = T.MapUtil.builder("id", pkg.getId())
|
// Map<String, String> pkgInfo = T.MapUtil.builder("id", pkg.getId())
|
||||||
.put("platform", pkg.getPlatform())
|
// .put("platform", pkg.getPlatform())
|
||||||
.put("identifier", pkg.getIdentifier())
|
// .put("identifier", pkg.getIdentifier())
|
||||||
.put("version", pkg.getVersion())
|
// .put("version", pkg.getVersion())
|
||||||
.build();
|
// .build();
|
||||||
|
//
|
||||||
// playbook
|
// // playbook
|
||||||
PlaybookEntity playbook = job.getPlaybook();
|
// PlaybookEntity playbook = job.getPlaybook();
|
||||||
Map<String, String> pbInfo = T.MapUtil.builder("id", playbook.getId())
|
// Map<String, String> pbInfo = T.MapUtil.builder("id", playbook.getId())
|
||||||
.put("name", playbook.getName())
|
// .put("name", playbook.getName())
|
||||||
.build();
|
// .build();
|
||||||
|
//
|
||||||
// response job info
|
// // response job info
|
||||||
Map<Object, Object> responseData = T.MapUtil.builder()
|
// Map<Object, Object> responseData = T.MapUtil.builder()
|
||||||
.put("id", job.getId())
|
// .put("id", job.getId())
|
||||||
.put("pkg", pkgInfo)
|
// .put("pkg", pkgInfo)
|
||||||
.put("playbook", pbInfo)
|
// .put("playbook", pbInfo)
|
||||||
.build();
|
// .build();
|
||||||
response.setCharacterEncoding("UTF-8");
|
// response.setCharacterEncoding("UTF-8");
|
||||||
response.setContentType("text/html; charset=UTF-8");
|
// response.setContentType("text/html; charset=UTF-8");
|
||||||
response.getWriter().write(T.JSONUtil.toJsonStr(responseData));
|
// response.getWriter().write(T.JSONUtil.toJsonStr(responseData));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@SaIgnore
|
// @SaIgnore
|
||||||
@PutMapping("/trace/{jobId}")
|
// @PutMapping("/trace/{jobId}")
|
||||||
public void trace(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestBody byte[] bytes,
|
// public void trace(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestBody byte[] bytes,
|
||||||
HttpServletResponse response) throws IOException {
|
// HttpServletResponse response) throws IOException {
|
||||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
// RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
// String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||||
if (!T.StrUtil.equals("online", status)) {
|
// if (!T.StrUtil.equals("online", status)) {
|
||||||
log.warn("[trace] [runner is offline] [token: {}]", token);
|
// log.warn("[trace] [runner is offline] [token: {}]", token);
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
// 追加到文件中
|
// // 追加到文件中
|
||||||
String content = T.StrUtil.str(bytes, T.CharsetUtil.CHARSET_UTF_8);
|
// String content = T.StrUtil.str(bytes, T.CharsetUtil.CHARSET_UTF_8);
|
||||||
jobService.appendTraceLogStrToFile(jobId, content);
|
// jobService.appendTraceLogStrToFile(jobId, content);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("[trace] [error] [job: {}]", jobId);
|
// log.error("[trace] [error] [job: {}]", jobId);
|
||||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
// response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@SaIgnore
|
// @SaIgnore
|
||||||
@PutMapping("/jobResult/{jobId}")
|
// @PutMapping("/jobResult/{jobId}")
|
||||||
public void jobResult(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestParam String state,
|
// public void jobResult(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestParam String state,
|
||||||
@RequestParam(value = "file", required = false) MultipartFile pcapFile,
|
// @RequestParam(value = "file", required = false) MultipartFile pcapFile,
|
||||||
HttpServletResponse response) throws IOException {
|
// HttpServletResponse response) throws IOException {
|
||||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
// RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
// String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||||
if (!T.StrUtil.equals("online", status)) {
|
// if (!T.StrUtil.equals("online", status)) {
|
||||||
log.warn("[trace] [runner is offline] [token: {}]", token);
|
// log.warn("[trace] [runner is offline] [token: {}]", token);
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
// response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 更新任务状态
|
// // 更新任务状态
|
||||||
jobService.updateJobResult(jobId, state, pcapFile);
|
// jobService.updateJobResult(jobId, state, pcapFile);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
@@ -14,6 +14,4 @@ public interface JobDao extends BaseMapper<JobEntity>{
|
|||||||
|
|
||||||
List<JobEntity> queryList(IPage page, Map<String, Object> params);
|
List<JobEntity> queryList(IPage page, Map<String, Object> params);
|
||||||
|
|
||||||
JobEntity getPendingJobByPlatform(@Param("platform") String platform);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package net.geedge.asw.module.runner.dao;
|
package net.geedge.asw.module.runner.dao;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PlaybookDao extends BaseMapper<PlaybookEntity>{
|
public interface PlaybookDao extends BaseMapper<PlaybookEntity>{
|
||||||
|
|
||||||
|
PlaybookEntity queryInfo(@Param("workspaceId") String workspaceId, @Param("id") String id);
|
||||||
|
|
||||||
|
List<PlaybookEntity> queryList(Page page, @Param("workspaceId") String workspaceId, @Param("params") Map params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("job")
|
@TableName("job")
|
||||||
@@ -15,12 +15,10 @@ public class JobEntity {
|
|||||||
|
|
||||||
@TableId(type = IdType.ASSIGN_UUID)
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
private String playbookId;
|
|
||||||
private String packageId;
|
private String packageId;
|
||||||
private String runnerId;
|
private String envId;
|
||||||
private String scheduleId;
|
private String playbookId;
|
||||||
private String signatureIds;
|
private String playbookParam;
|
||||||
private String tags;
|
|
||||||
private Long startTimestamp;
|
private Long startTimestamp;
|
||||||
private Long endTimestamp;
|
private Long endTimestamp;
|
||||||
private String status;
|
private String status;
|
||||||
@@ -35,17 +33,14 @@ public class JobEntity {
|
|||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String workbookId;
|
private String environmentId;
|
||||||
|
|
||||||
@TableField(exist = false)
|
|
||||||
private ApplicationEntity application;
|
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
@JsonProperty(value = "package")
|
@JsonProperty(value = "package")
|
||||||
private PackageEntity pkg;
|
private PackageEntity pkg;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private RunnerEntity runner;
|
private EnvironmentEntity environment;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private PlaybookEntity playbook;
|
private PlaybookEntity playbook;
|
||||||
|
|||||||
@@ -4,12 +4,17 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("pcap")
|
@TableName("pcap")
|
||||||
public class PcapEntity {
|
public class PcapEntity {
|
||||||
@@ -41,9 +46,14 @@ public class PcapEntity {
|
|||||||
private PackageEntity pkg;
|
private PackageEntity pkg;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private RunnerEntity runner;
|
private EnvironmentEntity environment;
|
||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private PlaybookEntity playbook;
|
private PlaybookEntity playbook;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Path getCommonPcapFilePath() {
|
||||||
|
return Path.of(T.WebPathUtil.getRootPath(), this.workspaceId, "pcap_comment", this.id + ".pcapng");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package net.geedge.asw.module.runner.entity;
|
package net.geedge.asw.module.runner.entity;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("playbook")
|
@TableName("playbook")
|
||||||
@@ -12,10 +14,9 @@ public class PlaybookEntity {
|
|||||||
@TableId(type = IdType.ASSIGN_UUID)
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private String appId;
|
|
||||||
private String tags;
|
private String tags;
|
||||||
private String script;
|
private String path;
|
||||||
private Long opVersion;
|
private String description;
|
||||||
|
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
private Long updateTimestamp;
|
private Long updateTimestamp;
|
||||||
@@ -24,4 +25,10 @@ public class PlaybookEntity {
|
|||||||
|
|
||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity createUser;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private SysUserEntity updateUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package net.geedge.asw.module.runner.job;
|
||||||
|
|
||||||
|
import cn.hutool.http.Header;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
|
import net.geedge.asw.module.runner.service.IJobService;
|
||||||
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
|
import net.geedge.asw.module.runner.util.RunnerConstant;
|
||||||
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
import org.quartz.DisallowConcurrentExecution;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
|
@DisallowConcurrentExecution
|
||||||
|
public class JobPlaybookExecResultChecker extends QuartzJobBean {
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPcapService pcapService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IJobService jobService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
|
||||||
|
|
||||||
|
Thread.currentThread().setName("JobPlaybookExecResultChecker");
|
||||||
|
|
||||||
|
log.info("[JobPlaybookExecResultChecker] [begin]");
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
sw.start();
|
||||||
|
try {
|
||||||
|
this.playbookExecResultChecker();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[JobPlaybookExecResultChecker] [error]");
|
||||||
|
} finally {
|
||||||
|
sw.stop();
|
||||||
|
}
|
||||||
|
log.info("[JobPlaybookExecResultChecker] [finshed] [Run Time: {}]", sw.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playbookExecResultChecker() {
|
||||||
|
Set<Map.Entry<String, String>> entryList = Constants.PLAYBOOK_EXECUTOR_RESULT.entrySet();
|
||||||
|
if (entryList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, String> entry : entryList) {
|
||||||
|
Thread.ofVirtual().start(() -> {
|
||||||
|
String tid = entry.getKey();
|
||||||
|
String jobId = entry.getValue();
|
||||||
|
JobEntity job = jobService.getById(jobId);
|
||||||
|
EnvironmentEntity environment = environmentService.getById(job.getEnvId());
|
||||||
|
log.info("[playbookExecResultChecker] [tid: {}] [jobId: {}] [envId]", tid, jobId, environment.getId());
|
||||||
|
|
||||||
|
JSONObject paramJSONObject = environment.getParamJSONObject();
|
||||||
|
String url = paramJSONObject.getStr("url");
|
||||||
|
String token = paramJSONObject.getStr("token");
|
||||||
|
HttpRequest request = T.HttpUtil.createGet(String.format("%s/api/v1/env/playbook/%s", url, tid));
|
||||||
|
request.header("Authorization", token);
|
||||||
|
|
||||||
|
HttpResponse response = request.execute();
|
||||||
|
log.info("[playbookExecResultChecker] [env: {}] [status: {}]", environment.getId(), response.getStatus());
|
||||||
|
|
||||||
|
File destination = null;
|
||||||
|
if (response.isOk()) {
|
||||||
|
// file
|
||||||
|
if (MediaType.APPLICATION_OCTET_STREAM_VALUE.equals(response.header(Header.CONTENT_TYPE.getValue()))) {
|
||||||
|
|
||||||
|
String fileName = response.header(Header.CONTENT_DISPOSITION).split("filename=")[1];
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[playbookExecResultChecker] [env: {}] [result fileName: {}]", environment.getId(), fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = T.FileUtil.file(Constants.TEMP_PATH, fileName);
|
||||||
|
T.FileUtil.writeBytes(response.bodyBytes(), destination);
|
||||||
|
Resource fileResource = new FileSystemResource(destination);
|
||||||
|
// upload pcap file
|
||||||
|
PcapEntity pcapEntity = pcapService.savePcap(fileResource, "", job.getWorkspaceId(), job.getCreateUserId());
|
||||||
|
job.setPcapId(pcapEntity.getId());
|
||||||
|
job.setStatus(RunnerConstant.JobStatus.PASSED.getValue());
|
||||||
|
job.setEndTimestamp(System.currentTimeMillis());
|
||||||
|
job.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
jobService.updateById(job);
|
||||||
|
Constants.PLAYBOOK_EXECUTOR_RESULT.remove(tid);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
String result = response.body();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[playbookExecResultChecker] [env: {}] [result: {}]", environment.getId(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(result);
|
||||||
|
if (T.ObjectUtil.equal(RCode.SUCCESS.getCode(), jsonObject.getInt("code"))) {
|
||||||
|
JSONObject data = jsonObject.getJSONObject("data");
|
||||||
|
String status = data.getStr("status");
|
||||||
|
if (!RunnerConstant.JobStatus.RUNNING.getValue().equals(status)) {
|
||||||
|
job.setStatus(RunnerConstant.JobStatus.FAILED.getValue());
|
||||||
|
job.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
job.setEndTimestamp(System.currentTimeMillis());
|
||||||
|
jobService.updateById(job);
|
||||||
|
Constants.PLAYBOOK_EXECUTOR_RESULT.remove(tid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (destination != null) {
|
||||||
|
T.FileUtil.del(destination);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package net.geedge.asw.module.runner.job;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
|
import net.geedge.asw.module.app.service.IPackageService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
|
import net.geedge.asw.module.runner.service.IJobService;
|
||||||
|
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||||
|
import net.geedge.asw.module.runner.util.RunnerConstant;
|
||||||
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
|
import org.quartz.DisallowConcurrentExecution;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@DisallowConcurrentExecution
|
||||||
|
public class JobPlaybookExecutor extends QuartzJobBean {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IJobService jobService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPackageService packageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPlaybookService playbookService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext context) {
|
||||||
|
Thread.currentThread().setName("JobPlaybookExecutor");
|
||||||
|
|
||||||
|
log.info("[JobPlaybookExecutor] [begin]");
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
sw.start();
|
||||||
|
try {
|
||||||
|
this.playbookExecutor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[JobPlaybookExecutor] [error]");
|
||||||
|
} finally {
|
||||||
|
sw.stop();
|
||||||
|
}
|
||||||
|
log.info("[JobPlaybookExecutor] [finshed] [Run Time: {}]", sw.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void playbookExecutor() {
|
||||||
|
List<JobEntity> list = jobService.list(new LambdaQueryWrapper<JobEntity>().eq(JobEntity::getStatus, RunnerConstant.JobStatus.CREATED.getValue()));
|
||||||
|
Map<String, List<JobEntity>> jobByEnvList = list.stream().collect(Collectors.groupingBy(JobEntity::getEnvId));
|
||||||
|
for (Map.Entry<String, List<JobEntity>> jobByEnv : jobByEnvList.entrySet()) {
|
||||||
|
String envId = jobByEnv.getKey();
|
||||||
|
List<JobEntity> jobList = jobByEnv.getValue();
|
||||||
|
Thread.ofVirtual().start(() -> {
|
||||||
|
for (JobEntity job : jobList) {
|
||||||
|
List<JobEntity> JobRunList = jobService.list(new LambdaQueryWrapper<JobEntity>().eq(JobEntity::getStatus, RunnerConstant.JobStatus.RUNNING.getValue()).eq(JobEntity::getEnvId, envId));
|
||||||
|
if (T.CollUtil.isNotEmpty(JobRunList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EnvironmentEntity environment = environmentService.getById(envId);
|
||||||
|
if (!environment.getStatus().equals(1)) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[playbookExecutor] [environment is not available] [jobId: {}] [envId: {}]", job.getId(), environment.getId());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = null;
|
||||||
|
String playbookId = job.getPlaybookId();
|
||||||
|
String packageId = job.getPackageId();
|
||||||
|
PackageEntity packageEntity = packageService.getById(packageId);
|
||||||
|
File packageFile = T.FileUtil.file(packageEntity.getPath());
|
||||||
|
String packageName = packageEntity.getIdentifier();
|
||||||
|
PlaybookEntity playbook = playbookService.getById(playbookId);
|
||||||
|
File playbookFile = T.FileUtil.file(playbook.getPath());
|
||||||
|
|
||||||
|
log.info("[playbookExecutor] [jobId: {}] [envId: {}] [playbookId: {}] [packageId: {}]", job.getId(), environment.getId(), playbookId, packageId);
|
||||||
|
|
||||||
|
JSONObject paramJSONObject = environment.getParamJSONObject();
|
||||||
|
String url = paramJSONObject.getStr("url");
|
||||||
|
String token = paramJSONObject.getStr("token");
|
||||||
|
|
||||||
|
HttpRequest request = T.HttpUtil.createPost(String.format("%s/api/v1/env/playbook", url));
|
||||||
|
request.form("files", packageFile, playbookFile);
|
||||||
|
request.form("packageName", packageName);
|
||||||
|
request.header("Authorization", token);
|
||||||
|
|
||||||
|
HttpResponse response = request.execute();
|
||||||
|
log.info("[playbookExecutor] [env] [status: {}]", environment.getId(), response.getStatus());
|
||||||
|
if (response.isOk()) {
|
||||||
|
result = response.body();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[playbookExecutor] [env: {}] [result: {}]", environment.getId(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(result)) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = T.JSONUtil.parseObj(result);
|
||||||
|
if (T.ObjectUtil.equal(RCode.SUCCESS.getCode(), jsonObject.getInt("code"))) {
|
||||||
|
JSONObject data = jsonObject.getJSONObject("data");
|
||||||
|
String tid = data.getStr("tid");
|
||||||
|
Constants.PLAYBOOK_EXECUTOR_RESULT.put(tid, job.getId());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[playbookExecutor] [parse result error] [result: {}]", job.getId(), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update job status, starTime, updateTimestamp
|
||||||
|
jobService.update(new LambdaUpdateWrapper<JobEntity>()
|
||||||
|
.set(JobEntity::getStatus, RunnerConstant.JobStatus.RUNNING.getValue())
|
||||||
|
.set(JobEntity::getUpdateTimestamp, System.currentTimeMillis())
|
||||||
|
.set(JobEntity::getStartTimestamp, System.currentTimeMillis())
|
||||||
|
.eq(JobEntity::getId, job.getId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package net.geedge.asw.module.runner.service;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -18,10 +17,10 @@ public interface IJobService extends IService<JobEntity>{
|
|||||||
|
|
||||||
void removeJob(List<String> ids);
|
void removeJob(List<String> ids);
|
||||||
|
|
||||||
JobEntity assignPendingJob(String id, String platform);
|
// JobEntity assignPendingJob(String id, String platform);
|
||||||
|
//
|
||||||
void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException;
|
// void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException;
|
||||||
|
//
|
||||||
void updateJobResult(String jobId, String state, MultipartFile pcapFile);
|
// void updateJobResult(String jobId, String state, MultipartFile pcapFile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ public interface IPcapService extends IService<PcapEntity>{
|
|||||||
|
|
||||||
Page queryList(Map<String, Object> params);
|
Page queryList(Map<String, Object> params);
|
||||||
|
|
||||||
PcapEntity savePcap(String jobId, Resource fileResource);
|
|
||||||
|
|
||||||
PcapEntity savePcap(Resource fileResource,String... params);
|
PcapEntity savePcap(Resource fileResource,String... params);
|
||||||
|
|
||||||
void deletePcap(String... ids);
|
void deletePcap(String... ids);
|
||||||
@@ -22,4 +20,8 @@ public interface IPcapService extends IService<PcapEntity>{
|
|||||||
void parse2session(String... ids);
|
void parse2session(String... ids);
|
||||||
|
|
||||||
void unparse2session(String[] ids);
|
void unparse2session(String[] ids);
|
||||||
|
|
||||||
|
String generateKibanaDiscoverUrl(String workspaceId, String pcapIds, String protocol, String streamId);
|
||||||
|
|
||||||
|
String generateKibanaDashboardUrl(String workspaceId, String pcapIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
package net.geedge.asw.module.runner.service;
|
package net.geedge.asw.module.runner.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface IPlaybookService extends IService<PlaybookEntity>{
|
public interface IPlaybookService extends IService<PlaybookEntity>{
|
||||||
|
|
||||||
|
PlaybookEntity detail(String workspaceId, String id);
|
||||||
|
|
||||||
|
Page queryList(String workspaceId, Map params);
|
||||||
|
|
||||||
|
PlaybookEntity savePlaybook(String workspaceId, MultipartFile file, String name, String description);
|
||||||
|
|
||||||
|
void delete(String workspaceId, String ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package net.geedge.asw.module.runner.service;
|
//package net.geedge.asw.module.runner.service;
|
||||||
|
//
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
//import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
//import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||||
|
//
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
public interface IRunnerService extends IService<RunnerEntity>{
|
//public interface IRunnerService extends IService<RunnerEntity>{
|
||||||
|
//
|
||||||
Page queryList(Map<String, Object> params);
|
// Page queryList(Map<String, Object> params);
|
||||||
|
//
|
||||||
RunnerEntity saveRunner(RunnerEntity entity);
|
// RunnerEntity saveRunner(RunnerEntity entity);
|
||||||
|
//
|
||||||
RunnerEntity updateRunner(RunnerEntity entity);
|
// RunnerEntity updateRunner(RunnerEntity entity);
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -1,33 +1,25 @@
|
|||||||
package net.geedge.asw.module.runner.service.impl;
|
package net.geedge.asw.module.runner.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
import net.geedge.asw.module.app.service.IApplicationService;
|
|
||||||
import net.geedge.asw.module.app.service.IPackageService;
|
import net.geedge.asw.module.app.service.IPackageService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
import net.geedge.asw.module.runner.dao.JobDao;
|
import net.geedge.asw.module.runner.dao.JobDao;
|
||||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
|
||||||
import net.geedge.asw.module.runner.service.IJobService;
|
import net.geedge.asw.module.runner.service.IJobService;
|
||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
|
||||||
import net.geedge.asw.module.runner.service.IPlaybookService;
|
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||||
import net.geedge.asw.module.runner.service.IRunnerService;
|
|
||||||
import net.geedge.asw.module.runner.util.RunnerConstant;
|
import net.geedge.asw.module.runner.util.RunnerConstant;
|
||||||
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
|
||||||
import net.geedge.asw.module.workbook.util.WorkbookConstant;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -39,10 +31,7 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
|
|||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPcapService pcapService;
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IRunnerService runnerService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPlaybookService playbookService;
|
private IPlaybookService playbookService;
|
||||||
@@ -50,11 +39,6 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IPackageService packageService;
|
private IPackageService packageService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IApplicationService applicationService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IWorkbookResourceService workbookResourceService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rootPath/result/{jobId}
|
* rootPath/result/{jobId}
|
||||||
@@ -71,19 +55,14 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
|
|||||||
JobEntity job = this.getById(id);
|
JobEntity job = this.getById(id);
|
||||||
T.VerifyUtil.is(job).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
T.VerifyUtil.is(job).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
RunnerEntity runner = runnerService.getById(job.getRunnerId());
|
EnvironmentEntity env = environmentService.getById(job.getEnvId());
|
||||||
job.setRunner(runner);
|
job.setEnvironment(env);
|
||||||
|
|
||||||
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
||||||
job.setPlaybook(playbook);
|
job.setPlaybook(playbook);
|
||||||
|
|
||||||
PackageEntity pkg = packageService.getById(job.getPackageId());
|
PackageEntity pkg = packageService.getById(job.getPackageId());
|
||||||
job.setPkg(pkg);
|
job.setPkg(pkg);
|
||||||
|
|
||||||
if (T.ObjectUtil.isNotNull(playbook)) {
|
|
||||||
ApplicationEntity application = applicationService.getById(playbook.getAppId());
|
|
||||||
job.setApplication(application);
|
|
||||||
}
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,13 +81,11 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
|
|||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setStatus(RunnerConstant.JobStatus.CREATED.getValue());
|
||||||
|
|
||||||
// save
|
// save
|
||||||
this.save(entity);
|
this.save(entity);
|
||||||
|
|
||||||
// workbook resource
|
|
||||||
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.JOB.getValue());
|
|
||||||
|
|
||||||
// trace log file path
|
// trace log file path
|
||||||
File traceLogFile = T.FileUtil.file(this.getJobResultPath(entity.getId()), "trace.log");
|
File traceLogFile = T.FileUtil.file(this.getJobResultPath(entity.getId()), "trace.log");
|
||||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||||
@@ -122,63 +99,61 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
|
|||||||
public void removeJob(List<String> ids) {
|
public void removeJob(List<String> ids) {
|
||||||
// remove
|
// remove
|
||||||
this.removeBatchByIds(ids);
|
this.removeBatchByIds(ids);
|
||||||
// workbook resource
|
|
||||||
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.JOB.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public synchronized JobEntity assignPendingJob(String runnerId, String platform) {
|
// public synchronized JobEntity assignPendingJob(String runnerId, String platform) {
|
||||||
if (T.StrUtil.hasEmpty(runnerId, platform)) {
|
// if (T.StrUtil.hasEmpty(runnerId, platform)) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
// query
|
// // query
|
||||||
JobEntity job = this.getBaseMapper().getPendingJobByPlatform(platform);
|
// JobEntity job = this.getBaseMapper().getPendingJobByPlatform(platform);
|
||||||
if (T.ObjectUtil.isNotNull(job)) {
|
// if (T.ObjectUtil.isNotNull(job)) {
|
||||||
// update
|
// // update
|
||||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
// this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||||
.set(JobEntity::getRunnerId, runnerId)
|
// .set(JobEntity::getRunnerId, runnerId)
|
||||||
.set(JobEntity::getStatus, RunnerConstant.JobStatus.RUNNING.getValue())
|
// .set(JobEntity::getStatus, RunnerConstant.JobStatus.RUNNING.getValue())
|
||||||
.set(JobEntity::getStartTimestamp, System.currentTimeMillis())
|
// .set(JobEntity::getStartTimestamp, System.currentTimeMillis())
|
||||||
.eq(JobEntity::getId, job.getId())
|
// .eq(JobEntity::getId, job.getId())
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
return job;
|
// return job;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException {
|
// public void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException {
|
||||||
try {
|
// try {
|
||||||
JobEntity job = this.getById(jobId);
|
// JobEntity job = this.getById(jobId);
|
||||||
if (T.StrUtil.isEmpty(job.getLogPath())) {
|
// if (T.StrUtil.isEmpty(job.getLogPath())) {
|
||||||
File traceLogFile = T.FileUtil.file(this.getJobResultPath(jobId), "trace.log");
|
// File traceLogFile = T.FileUtil.file(this.getJobResultPath(jobId), "trace.log");
|
||||||
job.setLogPath(traceLogFile.getPath());
|
// job.setLogPath(traceLogFile.getPath());
|
||||||
}
|
// }
|
||||||
// append content
|
// // append content
|
||||||
T.FileUtil.appendString(content, T.FileUtil.file(job.getLogPath()), T.CharsetUtil.CHARSET_UTF_8);
|
// T.FileUtil.appendString(content, T.FileUtil.file(job.getLogPath()), T.CharsetUtil.CHARSET_UTF_8);
|
||||||
} catch (IORuntimeException e) {
|
// } catch (IORuntimeException e) {
|
||||||
log.error(e, "[appendTraceLogStrToFile] [error] [job: {}] [content: {}]", jobId, content);
|
// log.error(e, "[appendTraceLogStrToFile] [error] [job: {}] [content: {}]", jobId, content);
|
||||||
throw new RuntimeException(e.getMessage());
|
// throw new RuntimeException(e.getMessage());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
// @Transactional(rollbackFor = Exception.class)
|
||||||
public void updateJobResult(String jobId, String state, MultipartFile pcapFile) {
|
// public void updateJobResult(String jobId, String state, MultipartFile pcapFile) {
|
||||||
String pcapId = T.StrUtil.EMPTY;
|
// String pcapId = T.StrUtil.EMPTY;
|
||||||
// save pcap file
|
// // save pcap file
|
||||||
if (T.ObjectUtil.isNotNull(pcapFile)) {
|
// if (T.ObjectUtil.isNotNull(pcapFile)) {
|
||||||
PcapEntity pcapEntity = pcapService.savePcap(jobId, pcapFile.getResource());
|
// PcapEntity pcapEntity = pcapService.savePcap(jobId, pcapFile.getResource());
|
||||||
pcapId = pcapEntity.getId();
|
// pcapId = pcapEntity.getId();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// update job status&pcap_id
|
// // update job status&pcap_id
|
||||||
state = T.StrUtil.equals("success", state) ? RunnerConstant.JobStatus.PASSED.getValue() : state;
|
// state = T.StrUtil.equals("success", state) ? RunnerConstant.JobStatus.PASSED.getValue() : state;
|
||||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
// this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||||
.set(JobEntity::getStatus, state)
|
// .set(JobEntity::getStatus, state)
|
||||||
.set(T.StrUtil.isNotEmpty(pcapId), JobEntity::getPcapId, pcapId)
|
// .set(T.StrUtil.isNotEmpty(pcapId), JobEntity::getPcapId, pcapId)
|
||||||
.set(JobEntity::getEndTimestamp, System.currentTimeMillis())
|
// .set(JobEntity::getEndTimestamp, System.currentTimeMillis())
|
||||||
.eq(JobEntity::getId, jobId)
|
// .eq(JobEntity::getId, jobId)
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package net.geedge.asw.module.runner.service.impl;
|
package net.geedge.asw.module.runner.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.net.URLEncodeUtil;
|
||||||
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@@ -10,19 +15,19 @@ import net.geedge.asw.common.config.SpringContextUtils;
|
|||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
import net.geedge.asw.common.util.RCode;
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
|
||||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||||
import net.geedge.asw.module.app.service.IApplicationService;
|
import net.geedge.asw.module.app.service.IApplicationService;
|
||||||
import net.geedge.asw.module.app.service.IPackageService;
|
import net.geedge.asw.module.app.service.IPackageService;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.feign.client.KibanaClient;
|
||||||
import net.geedge.asw.module.runner.dao.PcapDao;
|
import net.geedge.asw.module.runner.dao.PcapDao;
|
||||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
|
||||||
import net.geedge.asw.module.runner.service.IJobService;
|
import net.geedge.asw.module.runner.service.IJobService;
|
||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
import net.geedge.asw.module.runner.service.IPlaybookService;
|
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||||
import net.geedge.asw.module.runner.service.IRunnerService;
|
|
||||||
import net.geedge.asw.module.runner.util.PcapParserThread;
|
import net.geedge.asw.module.runner.util.PcapParserThread;
|
||||||
import net.geedge.asw.module.runner.util.RunnerConstant;
|
import net.geedge.asw.module.runner.util.RunnerConstant;
|
||||||
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
||||||
@@ -54,14 +59,14 @@ import java.util.stream.Collectors;
|
|||||||
public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements IPcapService {
|
public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements IPcapService {
|
||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
@Value("${sharkdApi.host:127.0.0.1}")
|
@Value("${sharkdApi.host:http://127.0.0.1}")
|
||||||
private String sharkdApiHostAddr;
|
private String sharkdApiHostAddr;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IJobService jobService;
|
private IJobService jobService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRunnerService runnerService;
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPlaybookService playbookService;
|
private IPlaybookService playbookService;
|
||||||
@@ -78,6 +83,15 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IWorkspaceService workspaceService;
|
private IWorkspaceService workspaceService;
|
||||||
|
|
||||||
|
@Value("${kibana.url:127.0.0.1:5601}")
|
||||||
|
private String kibanaUrl;
|
||||||
|
|
||||||
|
@jakarta.annotation.Resource
|
||||||
|
private KibanaClient kibanaClient;
|
||||||
|
|
||||||
|
@Value("${controller.url:http://127.0.0.1}")
|
||||||
|
private String aswControllerUrl;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PcapEntity queryInfo(String id) {
|
public PcapEntity queryInfo(String id) {
|
||||||
PcapEntity pcap = this.getById(id);
|
PcapEntity pcap = this.getById(id);
|
||||||
@@ -87,19 +101,14 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
if (T.ObjectUtil.isNotNull(job)) {
|
if (T.ObjectUtil.isNotNull(job)) {
|
||||||
pcap.setJobId(job.getId());
|
pcap.setJobId(job.getId());
|
||||||
|
|
||||||
RunnerEntity runner = runnerService.getById(job.getRunnerId());
|
EnvironmentEntity environment = environmentService.getById(job.getEnvId());
|
||||||
pcap.setRunner(runner);
|
pcap.setEnvironment(environment);
|
||||||
|
|
||||||
PackageEntity pkg = packageService.getById(job.getPackageId());
|
PackageEntity pkg = packageService.getById(job.getPackageId());
|
||||||
pcap.setPkg(pkg);
|
pcap.setPkg(pkg);
|
||||||
|
|
||||||
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
||||||
pcap.setPlaybook(playbook);
|
pcap.setPlaybook(playbook);
|
||||||
|
|
||||||
if (T.ObjectUtil.isNotNull(playbook)) {
|
|
||||||
ApplicationEntity application = applicationService.getById(playbook.getAppId());
|
|
||||||
pcap.setApplication(application);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pcap;
|
return pcap;
|
||||||
}
|
}
|
||||||
@@ -112,22 +121,18 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PcapEntity savePcap(String jobId, Resource fileResource) {
|
|
||||||
JobEntity job = jobService.getById(jobId);
|
|
||||||
return this.savePcap(fileResource, job.getTags(), job.getWorkbookId(), job.getWorkspaceId(), job.getCreateUserId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PcapEntity savePcap(Resource fileResource, String... params) {
|
public PcapEntity savePcap(Resource fileResource, String... params) {
|
||||||
String description = T.ArrayUtil.get(params, 0);
|
String description = T.ArrayUtil.get(params, 0);
|
||||||
String workbookId = T.ArrayUtil.get(params, 1);
|
String workspaceId = T.ArrayUtil.get(params, 1);
|
||||||
String workspaceId = T.ArrayUtil.get(params, 2);
|
String createUserId = T.ArrayUtil.get(params, 2);
|
||||||
String createUserId = T.StrUtil.emptyToDefault(T.ArrayUtil.get(params, 3), StpUtil.getLoginIdAsString());
|
if (T.StrUtil.isEmpty(createUserId)){
|
||||||
|
createUserId = StpUtil.getLoginIdAsString();
|
||||||
|
}
|
||||||
PcapEntity entity = new PcapEntity();
|
PcapEntity entity = new PcapEntity();
|
||||||
try {
|
try {
|
||||||
|
String pcapId = T.StrUtil.uuid();
|
||||||
|
entity.setId(pcapId);
|
||||||
entity.setName(fileResource.getFilename());
|
entity.setName(fileResource.getFilename());
|
||||||
entity.setDescription(description);
|
entity.setDescription(description);
|
||||||
|
|
||||||
@@ -140,7 +145,9 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
entity.setWorkspaceId(workspaceId);
|
entity.setWorkspaceId(workspaceId);
|
||||||
|
|
||||||
// path
|
// path
|
||||||
File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), workspaceId, fileResource.getFilename());
|
String fileExtName = T.StrUtil.emptyToDefault(T.FileUtil.extName(fileResource.getFilename()), "pcap");
|
||||||
|
String saveFileName = pcapId + "." + fileExtName;
|
||||||
|
File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), workspaceId, saveFileName);
|
||||||
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
|
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
|
||||||
entity.setPath(destination.getPath());
|
entity.setPath(destination.getPath());
|
||||||
|
|
||||||
@@ -156,9 +163,6 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
|
|
||||||
// save
|
// save
|
||||||
this.save(entity);
|
this.save(entity);
|
||||||
|
|
||||||
// workbook resource
|
|
||||||
workbookResourceService.saveResource(workbookId, entity.getId(), WorkbookConstant.ResourceType.PCAP.getValue());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e, "[savePcap] [error] [workspaceId: {}]", workspaceId);
|
log.error(e, "[savePcap] [error] [workspaceId: {}]", workspaceId);
|
||||||
throw new ASWException(RCode.ERROR);
|
throw new ASWException(RCode.ERROR);
|
||||||
@@ -173,6 +177,7 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
PcapEntity pcap = this.getById(id);
|
PcapEntity pcap = this.getById(id);
|
||||||
// remove file
|
// remove file
|
||||||
T.FileUtil.del(pcap.getPath());
|
T.FileUtil.del(pcap.getPath());
|
||||||
|
T.FileUtil.del(pcap.getCommonPcapFilePath());
|
||||||
|
|
||||||
// remove
|
// remove
|
||||||
this.removeById(id);
|
this.removeById(id);
|
||||||
@@ -193,6 +198,7 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
// parse thread config properties
|
// parse thread config properties
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.setProperty("sharkdApiHostAddr", this.sharkdApiHostAddr);
|
properties.setProperty("sharkdApiHostAddr", this.sharkdApiHostAddr);
|
||||||
|
properties.setProperty("aswControllerUrl", this.aswControllerUrl);
|
||||||
|
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
PcapEntity pcapEntity = this.getById(id);
|
PcapEntity pcapEntity = this.getById(id);
|
||||||
@@ -260,11 +266,153 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
|||||||
throw new RuntimeException("delete openSearch index error ", e);
|
throw new RuntimeException("delete openSearch index error ", e);
|
||||||
}
|
}
|
||||||
pcapEntity.setStatus(RunnerConstant.PcapStatus.UPLOADED.getValue());
|
pcapEntity.setStatus(RunnerConstant.PcapStatus.UPLOADED.getValue());
|
||||||
|
// reset summary
|
||||||
|
pcapEntity.setSummary("{}");
|
||||||
|
// del common pcap file
|
||||||
|
T.FileUtil.del(pcapEntity.getCommonPcapFilePath().toFile());
|
||||||
this.updateById(pcapEntity);
|
this.updateById(pcapEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. 根据 workspace_name 查询 index-pattern 是否存在
|
||||||
|
* 2. 不存在则创建索引
|
||||||
|
*
|
||||||
|
* 维护格式示例:
|
||||||
|
* {
|
||||||
|
* "type": "index-pattern",
|
||||||
|
* "id": "workspace_id",
|
||||||
|
* "attributes": {
|
||||||
|
* "title": "workspace-{workspace_name}-*"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @param workspaceId
|
||||||
|
* @param pcapIds
|
||||||
|
* @return kibana discover url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String generateKibanaDiscoverUrl(String workspaceId, String pcapIds, String protocol, String streamId) {
|
||||||
|
// verify
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||||
|
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
List<String> pcapIdList = T.StrUtil.split(pcapIds, ",").stream().filter(s -> T.StrUtil.isNotEmpty(s)).collect(Collectors.toList());
|
||||||
|
List<PcapEntity> pcapList = this.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, pcapIdList));
|
||||||
|
T.VerifyUtil.is(pcapList).notEmpty(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
// index name
|
||||||
|
String indexName = String.format("workspace-%s-*", workspace.getName());
|
||||||
|
|
||||||
|
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||||
|
String token = tokenInfo.getTokenValue();
|
||||||
|
|
||||||
|
JSONObject index = kibanaClient.findIndexPattern(token, "index-pattern" ,indexName);
|
||||||
|
JSONArray savedObjects = index.getJSONArray("saved_objects");
|
||||||
|
|
||||||
|
// check if index exists
|
||||||
|
boolean indexExists = savedObjects.stream()
|
||||||
|
.filter(obj -> {
|
||||||
|
JSONObject attributes = ((JSONObject) obj).getJSONObject("attributes");
|
||||||
|
if (T.ObjectUtil.isEmpty(attributes)) return false;
|
||||||
|
String title = attributes.getString("title");
|
||||||
|
return T.StrUtil.equals(indexName, title);
|
||||||
|
})
|
||||||
|
.findFirst()
|
||||||
|
.isPresent();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[generateKibanaDiscoverUrl] [idnex-pattern: {}] [exists: {}]", indexName, indexExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create index
|
||||||
|
if (T.BooleanUtil.negate(indexExists)) {
|
||||||
|
JSONObject attributes = new JSONObject();
|
||||||
|
attributes.put("title", indexName);
|
||||||
|
|
||||||
|
JSONObject body = new JSONObject();
|
||||||
|
body.put("attributes", attributes);
|
||||||
|
kibanaClient.saveIndexPattern(token, workspaceId, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build url
|
||||||
|
String baseUrl = UrlBuilder.ofHttp(kibanaUrl)
|
||||||
|
.addPath("/app/data-explorer/discover")
|
||||||
|
.addQuery("jwt", token)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
// build query param
|
||||||
|
String param1 = String.format("_a=(discover:(columns:!(_source),isDirty:!f,sort:!()),metadata:(indexPattern:'%s',view:discover))", workspaceId);
|
||||||
|
String param2 = "_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||||
|
|
||||||
|
String filter = pcapList.stream()
|
||||||
|
.map(PcapEntity::getId)
|
||||||
|
.map(pcapId -> "\"" + pcapId + "\"")
|
||||||
|
.collect(Collectors.joining("|", "pcap.id: (", ")"));
|
||||||
|
String param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s'))", filter);
|
||||||
|
|
||||||
|
if (T.StrUtil.isNotEmpty(protocol)){
|
||||||
|
String condition = T.StrUtil.concat(true, "proto:", protocol);
|
||||||
|
param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s && %s'))", filter, condition);
|
||||||
|
if (T.StrUtil.isNotEmpty(streamId)){
|
||||||
|
condition = T.StrUtil.concat(true, "pcap.", protocol, "_stream:", streamId);
|
||||||
|
param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s && %s'))", filter, condition);
|
||||||
|
}
|
||||||
|
// 处理 空格 &
|
||||||
|
param3 = URLEncodeUtil.encode(param3);
|
||||||
|
param3 = param3.replaceAll("&", "%26");
|
||||||
|
}
|
||||||
|
|
||||||
|
String query = String.format("?%s&%s&%s", param1, param2, param3);
|
||||||
|
String kibanaDiscoverUrl = baseUrl + "#" + query;
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[generateKibanaDiscoverUrl] [url: {}]", kibanaDiscoverUrl);
|
||||||
|
}
|
||||||
|
return kibanaDiscoverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateKibanaDashboardUrl(String workspaceId, String pcapIds) {
|
||||||
|
|
||||||
|
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||||
|
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
List<String> pcapIdList = T.StrUtil.split(pcapIds, ",").stream().filter(s -> T.StrUtil.isNotEmpty(s)).collect(Collectors.toList());
|
||||||
|
List<PcapEntity> pcapList = this.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, pcapIdList));
|
||||||
|
T.VerifyUtil.is(pcapList).notEmpty(RCode.SYS_RECORD_NOT_FOUND);
|
||||||
|
|
||||||
|
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||||
|
String token = tokenInfo.getTokenValue();
|
||||||
|
|
||||||
|
String dashboardId = T.JSONUtil.parseObj(workspace.getProperties()).getStr("dashboardId");
|
||||||
|
String dashboardName = String.format("workspace-%s", workspace.getName());
|
||||||
|
|
||||||
|
// build url
|
||||||
|
String baseUrl = UrlBuilder.ofHttp(kibanaUrl)
|
||||||
|
.addPath(T.StrUtil.concat(true, "/app/dashboards"))
|
||||||
|
.addQuery("jwt", token)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
String param1 = "_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||||
|
String filter = pcapList.stream()
|
||||||
|
.map(PcapEntity::getName)
|
||||||
|
.map(pcapName -> "\"" + pcapName + "\"")
|
||||||
|
.collect(Collectors.joining(" or ", "pcap.name:(", ")"));
|
||||||
|
String param2 = String.format("_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),query:(language:kuery,query:'%s'),timeRestore:!f,title:%s,viewMode:view)", filter, dashboardName);
|
||||||
|
String param3 = T.StrUtil.concat(true, "#/view/", dashboardId);
|
||||||
|
|
||||||
|
// 处理 空格 &
|
||||||
|
param2 = URLEncodeUtil.encode(param2);
|
||||||
|
param2 = param2.replaceAll("&", "%26");
|
||||||
|
|
||||||
|
String query = String.format("%s?%s&%s", param3, param1, param2);
|
||||||
|
String kibanaDashboardUrl = baseUrl + query;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[generateKibanaDashboardUrl] [url: {}]", kibanaDashboardUrl);
|
||||||
|
}
|
||||||
|
return kibanaDashboardUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calculate Parse Thread Timeout
|
* calculate Parse Thread Timeout
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,13 +1,84 @@
|
|||||||
package net.geedge.asw.module.runner.service.impl;
|
package net.geedge.asw.module.runner.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import net.geedge.asw.common.config.Query;
|
||||||
|
import net.geedge.asw.common.util.*;
|
||||||
import net.geedge.asw.module.runner.dao.PlaybookDao;
|
import net.geedge.asw.module.runner.dao.PlaybookDao;
|
||||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||||
import net.geedge.asw.module.runner.service.IPlaybookService;
|
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PlaybookServiceImpl extends ServiceImpl<PlaybookDao, PlaybookEntity> implements IPlaybookService {
|
public class PlaybookServiceImpl extends ServiceImpl<PlaybookDao, PlaybookEntity> implements IPlaybookService {
|
||||||
|
private final static Log log = Log.get();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlaybookEntity detail(String workspaceId, String id) {
|
||||||
|
PlaybookEntity playbook = this.baseMapper.queryInfo(workspaceId, id);
|
||||||
|
return playbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page queryList(String workspaceId, Map params) {
|
||||||
|
Page page = new Query(PlaybookEntity.class).getPage(params);
|
||||||
|
List<PlaybookEntity> playbookList = this.baseMapper.queryList(page, workspaceId, params);
|
||||||
|
page.setRecords(playbookList);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public PlaybookEntity savePlaybook(String workspaceId, MultipartFile file, String name, String description) {
|
||||||
|
|
||||||
|
List<PlaybookEntity> playbookList = this.baseMapper.selectList(new LambdaQueryWrapper<PlaybookEntity>().eq(PlaybookEntity::getWorkspaceId, workspaceId).eq(PlaybookEntity::getName, name));
|
||||||
|
if (T.CollUtil.isNotEmpty(playbookList)) {
|
||||||
|
throw new ASWException(RCode.PLAYBOOK_NAME_DUPLICATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaybookEntity playbook = new PlaybookEntity();
|
||||||
|
try {
|
||||||
|
playbook.setWorkspaceId(workspaceId);
|
||||||
|
playbook.setName(name);
|
||||||
|
playbook.setDescription(description);
|
||||||
|
playbook.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
playbook.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
playbook.setCreateTimestamp(System.currentTimeMillis());
|
||||||
|
playbook.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
|
|
||||||
|
// path
|
||||||
|
File destination = T.FileUtil.file(Constants.PLAYBOOK_FILES_DIR, name);
|
||||||
|
FileUtils.copyInputStreamToFile(file.getInputStream(), destination);
|
||||||
|
playbook.setPath(destination.getPath());
|
||||||
|
this.save(playbook);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[savePlaybook] [error] [file: {}]", file.getName());
|
||||||
|
T.FileUtil.del(description);
|
||||||
|
}
|
||||||
|
return playbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String workspaceId, String ids) {
|
||||||
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
|
for (String id : idList) {
|
||||||
|
PlaybookEntity entity = this.getById(id);
|
||||||
|
// remove file
|
||||||
|
T.FileUtil.del(entity.getPath());
|
||||||
|
|
||||||
|
// remove
|
||||||
|
this.removeById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
package net.geedge.asw.module.runner.service.impl;
|
//package net.geedge.asw.module.runner.service.impl;
|
||||||
|
//
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
//import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import net.geedge.asw.common.util.T;
|
//import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.runner.dao.RunnerDao;
|
//import net.geedge.asw.module.runner.dao.RunnerDao;
|
||||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
//import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||||
import net.geedge.asw.module.runner.service.IRunnerService;
|
//import net.geedge.asw.module.runner.service.IRunnerService;
|
||||||
import org.springframework.stereotype.Service;
|
//import org.springframework.stereotype.Service;
|
||||||
|
//
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
|
//
|
||||||
@Service
|
//@Service
|
||||||
public class RunnerServiceImpl extends ServiceImpl<RunnerDao, RunnerEntity> implements IRunnerService {
|
//public class RunnerServiceImpl extends ServiceImpl<RunnerDao, RunnerEntity> implements IRunnerService {
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public Page queryList(Map<String, Object> params) {
|
// public Page queryList(Map<String, Object> params) {
|
||||||
Page page = T.PageUtil.getPage(params);
|
// Page page = T.PageUtil.getPage(params);
|
||||||
List<RunnerEntity> jobList = this.getBaseMapper().queryList(page, params);
|
// List<RunnerEntity> jobList = this.getBaseMapper().queryList(page, params);
|
||||||
page.setRecords(jobList);
|
// page.setRecords(jobList);
|
||||||
return page;
|
// return page;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public RunnerEntity saveRunner(RunnerEntity entity) {
|
// public RunnerEntity saveRunner(RunnerEntity entity) {
|
||||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
// entity.setCreateTimestamp(System.currentTimeMillis());
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
// entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
// entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
// entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
//
|
||||||
// token
|
// // token
|
||||||
entity.setToken(T.IdUtil.fastSimpleUUID());
|
// entity.setToken(T.IdUtil.fastSimpleUUID());
|
||||||
|
//
|
||||||
// save
|
// // save
|
||||||
this.save(entity);
|
// this.save(entity);
|
||||||
return entity;
|
// return entity;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public RunnerEntity updateRunner(RunnerEntity entity) {
|
// public RunnerEntity updateRunner(RunnerEntity entity) {
|
||||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
// entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
// entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
//
|
||||||
// update
|
// // update
|
||||||
this.updateById(entity);
|
// this.updateById(entity);
|
||||||
return entity;
|
// return entity;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
@@ -4,15 +4,20 @@ import cn.hutool.log.Log;
|
|||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import feign.Response;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.geedge.asw.common.config.SpringContextUtils;
|
import net.geedge.asw.common.config.SpringContextUtils;
|
||||||
|
import net.geedge.asw.common.util.RCode;
|
||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.feign.client.GeoipClient;
|
import net.geedge.asw.module.feign.client.GeoipClient;
|
||||||
|
import net.geedge.asw.module.feign.client.PcapCommentClient;
|
||||||
import net.geedge.asw.module.feign.client.ZeekClient;
|
import net.geedge.asw.module.feign.client.ZeekClient;
|
||||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||||
import net.geedge.asw.module.runner.service.IPcapService;
|
import net.geedge.asw.module.runner.service.IPcapService;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.time.StopWatch;
|
import org.apache.commons.lang3.time.StopWatch;
|
||||||
import org.opensearch.client.opensearch.OpenSearchClient;
|
import org.opensearch.client.opensearch.OpenSearchClient;
|
||||||
|
import org.opensearch.client.opensearch._types.mapping.Property;
|
||||||
import org.opensearch.client.opensearch.core.BulkRequest;
|
import org.opensearch.client.opensearch.core.BulkRequest;
|
||||||
import org.opensearch.client.opensearch.core.BulkResponse;
|
import org.opensearch.client.opensearch.core.BulkResponse;
|
||||||
import org.opensearch.client.opensearch.core.bulk.BulkResponseItem;
|
import org.opensearch.client.opensearch.core.bulk.BulkResponseItem;
|
||||||
@@ -21,7 +26,12 @@ import org.opensearch.client.opensearch.indices.DeleteIndexRequest;
|
|||||||
import org.opensearch.client.opensearch.indices.ExistsRequest;
|
import org.opensearch.client.opensearch.indices.ExistsRequest;
|
||||||
import org.opensearch.client.opensearch.indices.IndexSettings;
|
import org.opensearch.client.opensearch.indices.IndexSettings;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -40,12 +50,14 @@ public class PcapParserThread implements Runnable {
|
|||||||
private ZeekClient zeekClient;
|
private ZeekClient zeekClient;
|
||||||
private GeoipClient geoipClient;
|
private GeoipClient geoipClient;
|
||||||
private OpenSearchClient openSearchClient;
|
private OpenSearchClient openSearchClient;
|
||||||
|
private PcapCommentClient pcapCommentClient;
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
pcapService = SpringContextUtils.getBean(IPcapService.class);
|
pcapService = SpringContextUtils.getBean(IPcapService.class);
|
||||||
zeekClient = (ZeekClient) SpringContextUtils.getBean("zeekClient");
|
zeekClient = (ZeekClient) SpringContextUtils.getBean("zeekClient");
|
||||||
geoipClient = (GeoipClient) SpringContextUtils.getBean("geoipClient");
|
geoipClient = (GeoipClient) SpringContextUtils.getBean("geoipClient");
|
||||||
openSearchClient = (OpenSearchClient) SpringContextUtils.getBean("openSearchClient");
|
openSearchClient = (OpenSearchClient) SpringContextUtils.getBean("openSearchClient");
|
||||||
|
pcapCommentClient = (PcapCommentClient) SpringContextUtils.getBean("pcapCommentClient");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,6 +74,8 @@ public class PcapParserThread implements Runnable {
|
|||||||
this.init();
|
this.init();
|
||||||
// parsing
|
// parsing
|
||||||
this.updateStatus(PcapStatus.PARSING.getValue());
|
this.updateStatus(PcapStatus.PARSING.getValue());
|
||||||
|
// add common to pcap
|
||||||
|
this.addCommonToPcap();
|
||||||
// parser
|
// parser
|
||||||
this.parser();
|
this.parser();
|
||||||
// indexed
|
// indexed
|
||||||
@@ -76,6 +90,27 @@ public class PcapParserThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add common to pacp
|
||||||
|
*/
|
||||||
|
private void addCommonToPcap() throws IOException {
|
||||||
|
// pcap common
|
||||||
|
Response response = pcapCommentClient.addCommon(T.FileUtil.file(pcapEntity.getPath()), properties.getProperty("aswControllerUrl"), pcapEntity.getId());
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("[addCommonToPcap] [response: {}]", null != response ? response.status() : RCode.ERROR.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == response || 200 != response.status()) {
|
||||||
|
throw new RuntimeException("Failed to add common to pcap");
|
||||||
|
}
|
||||||
|
|
||||||
|
// file path: /{path}/{workspace_id}/pcap_comment/{pcap_id}.pcapng
|
||||||
|
File destination = pcapEntity.getCommonPcapFilePath().toFile();
|
||||||
|
T.FileUtil.del(destination);
|
||||||
|
FileUtils.copyInputStreamToFile(response.body().asInputStream(), destination);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parser
|
* parser
|
||||||
*/
|
*/
|
||||||
@@ -96,25 +131,23 @@ public class PcapParserThread implements Runnable {
|
|||||||
|
|
||||||
// add custom field
|
// add custom field
|
||||||
String pcapId = pcapEntity.getId();
|
String pcapId = pcapEntity.getId();
|
||||||
String pcapName = T.FileUtil.getName(pcapEntity.getPath());
|
String pcapName = pcapEntity.getName();
|
||||||
Long tcpStream = 0L, udpStream = 0L;
|
|
||||||
|
|
||||||
String sharkdApiHostAddr = properties.getProperty("sharkdApiHostAddr", "127.0.0.1");
|
String sharkdApiHostAddr = properties.getProperty("sharkdApiHostAddr", "http://127.0.0.1");
|
||||||
for (Object obj : jsonArray) {
|
for (Object obj : jsonArray) {
|
||||||
JSONObject pojo = (JSONObject) obj;
|
JSONObject pojo = (JSONObject) obj;
|
||||||
pojo.put("pcap.id", pcapId);
|
pojo.put("pcap.id", pcapId);
|
||||||
pojo.put("pcap.name", pcapName);
|
pojo.put("pcap.name", pcapName);
|
||||||
|
|
||||||
String proto = T.MapUtil.getStr(pojo, "proto", "");
|
String proto = T.MapUtil.getStr(pojo, "proto", "");
|
||||||
|
Long streamId = T.MapUtil.getLong(pojo, "stream_id");
|
||||||
if (T.StrUtil.equalsIgnoreCase("tcp", proto)) {
|
if (T.StrUtil.equalsIgnoreCase("tcp", proto)) {
|
||||||
Long streamId = tcpStream++;
|
|
||||||
pojo.put("pcap.tcp_stream", streamId);
|
pojo.put("pcap.tcp_stream", streamId);
|
||||||
pojo.put("pcap.stream_url", String.format("http://%s/pcap/%s/tcp/%s", sharkdApiHostAddr, pcapId, streamId));
|
pojo.put("pcap.stream_url", String.format("%s/navi/pcap/%s/tcp/%s", sharkdApiHostAddr, pcapId, streamId));
|
||||||
}
|
}
|
||||||
if (T.StrUtil.equalsIgnoreCase("udp", proto)) {
|
if (T.StrUtil.equalsIgnoreCase("udp", proto)) {
|
||||||
Long streamId = udpStream++;
|
|
||||||
pojo.put("pcap.udp_stream", streamId);
|
pojo.put("pcap.udp_stream", streamId);
|
||||||
pojo.put("pcap.stream_url", String.format("http://%s/pcap/%s/udp/%s", sharkdApiHostAddr, pcapId, streamId));
|
pojo.put("pcap.stream_url", String.format("%s/navi/pcap/%s/udp/%s", sharkdApiHostAddr, pcapId, streamId));
|
||||||
}
|
}
|
||||||
|
|
||||||
String resp = T.MapUtil.getStr(pojo, "id.resp_h", "");
|
String resp = T.MapUtil.getStr(pojo, "id.resp_h", "");
|
||||||
@@ -186,6 +219,7 @@ public class PcapParserThread implements Runnable {
|
|||||||
.put("sessions", jsonArray.size())
|
.put("sessions", jsonArray.size())
|
||||||
.put("packets", packets)
|
.put("packets", packets)
|
||||||
.put("services", services)
|
.put("services", services)
|
||||||
|
.put("commentPath", pcapEntity.getCommonPcapFilePath().toString())
|
||||||
.build();
|
.build();
|
||||||
pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
|
pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
|
||||||
.set(PcapEntity::getSummary, T.JSONUtil.toJsonStr(m))
|
.set(PcapEntity::getSummary, T.JSONUtil.toJsonStr(m))
|
||||||
@@ -200,9 +234,7 @@ public class PcapParserThread implements Runnable {
|
|||||||
* @param jsonArray
|
* @param jsonArray
|
||||||
*/
|
*/
|
||||||
private void uploadToOpenSearch(JSONArray jsonArray) {
|
private void uploadToOpenSearch(JSONArray jsonArray) {
|
||||||
String pcapPath = pcapEntity.getPath();
|
String md5Hex = pcapEntity.getMd5();
|
||||||
String md5Hex = T.DigestUtil.md5Hex(T.FileUtil.file(pcapPath));
|
|
||||||
|
|
||||||
String workspaceName = pcapEntity.getWorkspace().getName();
|
String workspaceName = pcapEntity.getWorkspace().getName();
|
||||||
String indexName = String.format("workspace-%s-%s", workspaceName, md5Hex);
|
String indexName = String.format("workspace-%s-%s", workspaceName, md5Hex);
|
||||||
|
|
||||||
@@ -221,17 +253,116 @@ public class PcapParserThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create index with default settings
|
// create index with default settings
|
||||||
openSearchClient.indices().create(
|
// openSearchClient.indices().create(
|
||||||
new CreateIndexRequest.Builder()
|
// new CreateIndexRequest.Builder()
|
||||||
|
// .index(indexName)
|
||||||
|
// .settings(new IndexSettings.Builder().build())
|
||||||
|
// .build()
|
||||||
|
// );
|
||||||
|
CreateIndexRequest.Builder createIndexRequestBuilder = new CreateIndexRequest.Builder()
|
||||||
.index(indexName)
|
.index(indexName)
|
||||||
.settings(new IndexSettings.Builder().build())
|
.settings(new IndexSettings.Builder().build())
|
||||||
.build()
|
.mappings(m -> m.properties("conn_state", Property.of(p -> p.keyword(k -> k)))
|
||||||
|
.properties("dns", Property.of(p ->
|
||||||
|
p.object(o -> o.properties("AA", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("RA", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("RD", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("TC", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("TTLs", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("Z", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("answers", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("qclass", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("qclass_name", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("qtype", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("qtype_name", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("query", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("rcode", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("rcode_name", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("rejected", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("rtt", Property.of(p2 -> p2.float_(f -> f)))
|
||||||
|
.properties("trans_id", Property.of(p2 -> p2.long_(l -> l))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties("duration", Property.of(p -> p.float_(f -> f)))
|
||||||
|
.properties("history", Property.of(p -> p.keyword(k -> k)))
|
||||||
|
.properties("http", Property.of(p ->
|
||||||
|
p.object(o -> o.properties("host", Property.of(p2 -> p2.text(t -> t)))
|
||||||
|
.properties("method", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("orig_fuids", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("request_body_len", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("resp_fuids", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_mime_types", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("response_body_len", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("status_code", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("status_msg", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("trans_depth", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("uri", Property.of(p2 -> p2.text(t -> t)))
|
||||||
|
.properties("user_agent", Property.of(p2 -> p2.text(t -> t)))
|
||||||
|
.properties("version", Property.of(p2 -> p2.keyword(k -> k))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties("id", Property.of(p ->
|
||||||
|
p.object(o -> o.properties("orig_h", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("orig_p", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("resp_asn", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_asname", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_country", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_domain", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_h", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resp_p", Property.of(p2 -> p2.long_(l -> l))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties("local_orig", Property.of(p -> p.boolean_(b -> b)))
|
||||||
|
.properties("local_resp", Property.of(p -> p.boolean_(b -> b)))
|
||||||
|
.properties("missed_bytes", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("orig_bytes", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("orig_ip_bytes", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("orig_pkts", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("pcap", Property.of(p ->
|
||||||
|
p.object(o -> o.properties("id", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("name", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("stream_url", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("tcp_stream", Property.of(p2 -> p2.long_(l -> l)))
|
||||||
|
.properties("udp_stream", Property.of(p2 -> p2.long_(l -> l))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties("proto", Property.of(p -> p.keyword(k -> k)))
|
||||||
|
.properties("resp_bytes", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("resp_ip_bytes", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("resp_pkts", Property.of(p -> p.long_(l -> l)))
|
||||||
|
.properties("service", Property.of(p -> p.keyword(k -> k)))
|
||||||
|
.properties("ssl", Property.of(p ->
|
||||||
|
p.object(o -> o.properties("cert_chain_fps", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("cipher", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("curve", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("established", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("next_protocol", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("resumed", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("server_name", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("sni_matches_cert", Property.of(p2 -> p2.boolean_(b -> b)))
|
||||||
|
.properties("ssl_history", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("validation_status", Property.of(p2 -> p2.keyword(k -> k)))
|
||||||
|
.properties("version", Property.of(p2 -> p2.keyword(k -> k))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties("ts", Property.of(p -> p.float_(f -> f)))
|
||||||
|
.properties("time", Property.of(p -> p.keyword(f -> f)))
|
||||||
|
.properties("tunnel_parents", Property.of(p -> p.text(t -> t)))
|
||||||
|
.properties("uid", Property.of(p -> p.keyword(k -> k)))
|
||||||
);
|
);
|
||||||
|
openSearchClient.indices().create(createIndexRequestBuilder.build());
|
||||||
|
|
||||||
// upload data in bulk
|
// upload data in bulk
|
||||||
|
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||||
|
|
||||||
BulkRequest.Builder br = new BulkRequest.Builder();
|
BulkRequest.Builder br = new BulkRequest.Builder();
|
||||||
for (int i = 0; i < jsonArray.size(); i++) {
|
for (int i = 0; i < jsonArray.size(); i++) {
|
||||||
JSONObject jsonObject = (JSONObject) jsonArray.get(i);
|
JSONObject jsonObject = (JSONObject) jsonArray.get(i);
|
||||||
|
|
||||||
|
// 时间戳格式转换
|
||||||
|
String formatDate = this.convertTsToFormatDate(timeFormatter, jsonObject.getString("ts"));
|
||||||
|
jsonObject.put("time", formatDate);
|
||||||
|
|
||||||
String id = String.valueOf(i);
|
String id = String.valueOf(i);
|
||||||
br.operations(op -> op.index(
|
br.operations(op -> op.index(
|
||||||
idx -> idx.index(indexName)
|
idx -> idx.index(indexName)
|
||||||
@@ -255,6 +386,31 @@ public class PcapParserThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ts 时间戳格式转换
|
||||||
|
* 1725518539.484784 -> 2024-09-05 06:42:19.484
|
||||||
|
*/
|
||||||
|
private String convertTsToFormatDate(DateTimeFormatter formatter, String ts) {
|
||||||
|
try {
|
||||||
|
String[] parts = ts.split("\\.");
|
||||||
|
long seconds = Long.parseLong(parts[0]);
|
||||||
|
|
||||||
|
// 将小数部分转换为纳秒
|
||||||
|
int nanos = 0;
|
||||||
|
if (parts.length > 1) {
|
||||||
|
String fractionalPart = parts[1];
|
||||||
|
nanos = (int) (Double.parseDouble("0." + fractionalPart) * 1_000_000_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Instant instant = Instant.ofEpochSecond(seconds, nanos);
|
||||||
|
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
|
||||||
|
return zonedDateTime.format(formatter);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[convertTsToFormatDate] [error] [ts: {}]", ts);
|
||||||
|
}
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update pcap status
|
* update pcap status
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package net.geedge.asw.module.sys.controller;
|
package net.geedge.asw.module.sys.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import net.geedge.asw.common.util.ASWException;
|
import net.geedge.asw.common.util.ASWException;
|
||||||
@@ -9,61 +11,90 @@ import net.geedge.asw.common.util.RCode;
|
|||||||
import net.geedge.asw.common.util.T;
|
import net.geedge.asw.common.util.T;
|
||||||
import net.geedge.asw.module.sys.entity.SysRoleEntity;
|
import net.geedge.asw.module.sys.entity.SysRoleEntity;
|
||||||
import net.geedge.asw.module.sys.service.ISysRoleService;
|
import net.geedge.asw.module.sys.service.ISysRoleService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceMemberService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/role")
|
@RequestMapping("/api/v1/role")
|
||||||
public class SysRoleController {
|
public class SysRoleController {
|
||||||
|
|
||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysRoleService roleService;
|
private ISysRoleService roleService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IWorkspaceMemberService workspaceMemberService;
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public R detail(@PathVariable("id") String id) {
|
public R detail(@PathVariable("id") String id) {
|
||||||
SysRoleEntity entity = roleService.getById(id);
|
SysRoleEntity entity = roleService.detail(id);
|
||||||
return R.ok().putData("record", entity);
|
return R.ok().putData("record", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public R list(String ids, String name,
|
public R list(@RequestParam Map params) {
|
||||||
@RequestParam(defaultValue = "1") Integer current,
|
Page page = roleService.queryList(params);
|
||||||
@RequestParam(defaultValue = "20") Integer size,
|
|
||||||
@RequestParam(defaultValue = "name") String orderBy) {
|
|
||||||
QueryWrapper<SysRoleEntity> queryWrapper = new QueryWrapper<SysRoleEntity>();
|
|
||||||
queryWrapper.like(T.StrUtil.isNotBlank(name), "name", name).in(T.StrUtil.isNotBlank(ids), "id", ids.split(","));
|
|
||||||
Page<SysRoleEntity> page = Page.of(current, size);
|
|
||||||
page.addOrder(T.PageUtil.decodeOrderByStr(orderBy));
|
|
||||||
page = roleService.page(page, queryWrapper);
|
|
||||||
return R.ok(page);
|
return R.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public R add(@RequestBody SysRoleEntity entity) {
|
public R add(@RequestBody SysRoleEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull().and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY);
|
T.VerifyUtil.is(entity).notNull()
|
||||||
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY);
|
||||||
SysRoleEntity one = roleService.getOne(new QueryWrapper<SysRoleEntity>().lambda().eq(SysRoleEntity::getName, entity.getName()));
|
SysRoleEntity one = roleService.getOne(new QueryWrapper<SysRoleEntity>().lambda().eq(SysRoleEntity::getName, entity.getName()));
|
||||||
if (T.ObjectUtil.isNotNull(one)) {
|
if (T.ObjectUtil.isNotNull(one)) {
|
||||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
||||||
}
|
}
|
||||||
entity.setCreateTimestamp(T.DateUtil.current());
|
entity.setCreateTimestamp(T.DateUtil.current());
|
||||||
|
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||||
|
entity.setUpdateTimestamp(T.DateUtil.current());
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
roleService.saveOrUpdateRole(entity);
|
roleService.saveOrUpdateRole(entity);
|
||||||
return R.ok().putData("id", entity.getId());
|
return R.ok().putData("id", entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public R update(@RequestBody SysRoleEntity entity) {
|
public R update(@RequestBody SysRoleEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull().and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY);
|
T.VerifyUtil.is(entity).notNull()
|
||||||
entity.setCreateTimestamp(null);
|
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||||
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
SysRoleEntity one = roleService.getOne(new QueryWrapper<SysRoleEntity>().lambda().eq(SysRoleEntity::getName, entity.getName()));
|
||||||
|
SysRoleEntity role = roleService.getById(entity.getId());
|
||||||
|
if (role.getBuildIn() == 1) {
|
||||||
|
throw ASWException.builder().rcode(RCode.SYS_ROLE_BUILT_IN).build();
|
||||||
|
}
|
||||||
|
if (T.ObjectUtil.isNotNull(one) && !one.getId().equals(entity.getId())) {
|
||||||
|
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setUpdateTimestamp(T.DateUtil.current());
|
||||||
|
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||||
roleService.saveOrUpdateRole(entity);
|
roleService.saveOrUpdateRole(entity);
|
||||||
return R.ok().putData("id", entity.getId());
|
return R.ok().putData("id", entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public R delete(String[] ids) {
|
public R delete(String ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
roleService.removeBatchByIds(T.ListUtil.of(ids));
|
List<String> idList = T.ListUtil.of(ids.split(","));
|
||||||
log.info("delete Role, ids: {}", T.ArrayUtil.toString(ids));
|
List<SysRoleEntity> roleList = roleService.list(new LambdaQueryWrapper<SysRoleEntity>().eq(SysRoleEntity::getBuildIn, 1).in(SysRoleEntity::getId, idList));
|
||||||
|
if (T.CollectionUtil.isNotEmpty(roleList)) {
|
||||||
|
throw ASWException.builder().rcode(RCode.SYS_ROLE_BUILT_IN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<WorkspaceMemberEntity> list = workspaceMemberService.list(new LambdaQueryWrapper<WorkspaceMemberEntity>().in(WorkspaceMemberEntity::getRoleId, idList));
|
||||||
|
if (T.CollectionUtil.isNotEmpty(list)) {
|
||||||
|
throw ASWException.builder().rcode(RCode.SYS_ROLE_NOT_DELETE).build();
|
||||||
|
}
|
||||||
|
roleService.delete(idList);
|
||||||
|
log.info("Delete Role, ids: {}", T.ArrayUtil.toString(idList));
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
package net.geedge.asw.module.sys.controller;
|
package net.geedge.asw.module.sys.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import net.geedge.asw.common.util.*;
|
import net.geedge.asw.common.util.*;
|
||||||
import net.geedge.asw.module.sys.entity.SysRoleEntity;
|
|
||||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||||
import net.geedge.asw.module.sys.entity.SysUserRoleEntity;
|
|
||||||
import net.geedge.asw.module.sys.service.ISysRoleService;
|
|
||||||
import net.geedge.asw.module.sys.service.ISysUserRoleService;
|
|
||||||
import net.geedge.asw.module.sys.service.ISysUserService;
|
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||||
|
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
|
||||||
|
import net.geedge.asw.module.workspace.service.IWorkspaceMemberService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/user")
|
@RequestMapping("/api/v1/user")
|
||||||
@@ -24,81 +23,109 @@ public class SysUserController {
|
|||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService userService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysRoleService roleService;
|
private IWorkspaceMemberService workspaceMemberService;
|
||||||
@Autowired
|
|
||||||
private ISysUserRoleService uerRoleService;
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public R detail(@PathVariable("id") String id) {
|
public R detail(@PathVariable("id") String id) {
|
||||||
SysUserEntity entity = userService.getById(id);
|
SysUserEntity entity = userService.getById(id);
|
||||||
if (T.ObjectUtil.isNotNull(entity)) {
|
if (T.ObjectUtil.isNotNull(entity)) {
|
||||||
entity.setPwd(null);
|
entity.setPwd(null);
|
||||||
List<SysUserRoleEntity> userRoleList = uerRoleService.list(new LambdaQueryWrapper<SysUserRoleEntity>().eq(SysUserRoleEntity::getUserId, entity.getId()));
|
Map params = T.MapUtil.builder("userId", id).build();
|
||||||
if (T.CollUtil.isNotEmpty(userRoleList)) {
|
List<WorkspaceMemberEntity> workspaceMemberEntityList = workspaceMemberService.queryList(params);
|
||||||
List<String> roleIds = userRoleList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList());
|
entity.setWorkspaceRoles(workspaceMemberEntityList);
|
||||||
List<SysRoleEntity> roleList = roleService.listByIds(roleIds);
|
SysUserEntity createUser = userService.getOne(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getId, entity.getCreateUserId()));
|
||||||
entity.setRoles(roleList);
|
createUser.setPwd(null);
|
||||||
}
|
entity.setCreateUser(createUser);
|
||||||
|
SysUserEntity updateUser = userService.getOne(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getId, entity.getUpdateUserId()));
|
||||||
|
updateUser.setPwd(null);
|
||||||
|
entity.setUpdateUser(updateUser);
|
||||||
}
|
}
|
||||||
return R.ok().putData("record", entity);
|
return R.ok().putData("record", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public R list(String ids, String q,
|
public R list(@RequestParam Map<String, Object> params) {
|
||||||
@RequestParam(defaultValue = "1") Integer current,
|
Page<SysUserEntity> page = userService.queryList(params);
|
||||||
@RequestParam(defaultValue = "20") Integer size,
|
|
||||||
@RequestParam(defaultValue = "name") String orderBy) {
|
|
||||||
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
|
|
||||||
// 不查询 pwd 列
|
|
||||||
queryWrapper.select(SysUserEntity.class, entity -> !entity.getColumn().equals("pwd"));
|
|
||||||
queryWrapper.in(T.StrUtil.isNotEmpty(ids), "id", T.StrUtil.split(ids, ','));
|
|
||||||
if (T.StrUtil.isNotBlank(q)) {
|
|
||||||
queryWrapper.and(wrapper -> wrapper.like("name", q).or().like("user_name", q));
|
|
||||||
}
|
|
||||||
Page<SysUserEntity> page = Page.of(current, size);
|
|
||||||
page.addOrder(T.PageUtil.decodeOrderByStr(orderBy));
|
|
||||||
page = userService.page(page, queryWrapper);
|
|
||||||
return R.ok(page);
|
return R.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public R add(@RequestBody SysUserEntity entity) {
|
public R add(@RequestBody SysUserEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull().and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
T.VerifyUtil.is(entity).notNull()
|
||||||
.and(entity.getUserName()).notEmpty().and(entity.getPwd()).notEmpty();
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
SysUserEntity one = userService.getOne(
|
.and(entity.getUserName()).notEmpty(RCode.SYS_USER_NAME_CANNOT_EMPTY)
|
||||||
new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getUserName, entity.getUserName()));
|
.and(entity.getAccessLevel()).notEmpty(RCode.SYS_ACCESS_LEVEL_CANNOT_EMPTY)
|
||||||
if (T.ObjectUtil.isNotNull(one)) {
|
.and(entity.getWorkspaceRoles()).notEmpty(RCode.SYS_WORKSPACE_ROLES_CANNOT_EMPTY);
|
||||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
|
||||||
}
|
userService.saveUser(entity);
|
||||||
// 密码加密
|
|
||||||
entity.setPwd(T.AesUtil.encrypt(entity.getPwd(), Constants.AES_KEY));
|
|
||||||
entity.setCreateTimestamp(T.DateUtil.current());
|
|
||||||
userService.saveOrUpdateUser(entity);
|
|
||||||
return R.ok().putData("id", entity.getId());
|
return R.ok().putData("id", entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public R update(@RequestBody SysUserEntity entity) {
|
public R update(@RequestBody SysUserEntity entity) {
|
||||||
T.VerifyUtil.is(entity).notNull().and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY);
|
T.VerifyUtil.is(entity).notNull()
|
||||||
if (T.StrUtil.isNotBlank(entity.getPwd())) {
|
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||||
// 密码加密
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
entity.setPwd(T.AesUtil.encrypt(entity.getPwd(), Constants.AES_KEY));
|
.and(entity.getUserName()).notEmpty(RCode.SYS_USER_NAME_CANNOT_EMPTY)
|
||||||
} else {
|
.and(entity.getAccessLevel()).notEmpty(RCode.SYS_ACCESS_LEVEL_CANNOT_EMPTY)
|
||||||
entity.setPwd(null);
|
.and(entity.getWorkspaceRoles()).notEmpty(RCode.SYS_WORKSPACE_ROLES_CANNOT_EMPTY);
|
||||||
}
|
userService.updateUser(entity);
|
||||||
entity.setUserName(null);// username 不允许修改
|
|
||||||
entity.setCreateTimestamp(null);
|
|
||||||
userService.saveOrUpdateUser(entity);
|
|
||||||
return R.ok().putData("id", entity.getId());
|
return R.ok().putData("id", entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public R delete(String[] ids) {
|
public R delete(String ids) {
|
||||||
T.VerifyUtil.is(ids).notEmpty();
|
T.VerifyUtil.is(ids).notEmpty();
|
||||||
userService.removeBatchByIds(T.ListUtil.of(ids));
|
userService.delete(ids);
|
||||||
log.info("delete user, ids: {}", T.ArrayUtil.toString(ids));
|
log.info("delete user, ids: {}", ids);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/profile")
|
||||||
|
public R profile() {
|
||||||
|
return this.detail(StpUtil.getLoginIdAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/profile")
|
||||||
|
public R profile(@RequestBody SysUserEntity entity) {
|
||||||
|
T.VerifyUtil.is(entity).notNull()
|
||||||
|
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||||
|
.and(entity.getAccessLevel()).notEmpty(RCode.SYS_ACCESS_LEVEL_CANNOT_EMPTY);
|
||||||
|
|
||||||
|
SysUserEntity loginUser = userService.getById(StpUtil.getLoginIdAsString());
|
||||||
|
T.VerifyUtil.is(loginUser).notNull(RCode.USER_NO_LOGIN);
|
||||||
|
|
||||||
|
// update fields
|
||||||
|
String name = entity.getName();
|
||||||
|
String accessLevel = entity.getAccessLevel();
|
||||||
|
String pwd = entity.getPwd();
|
||||||
|
String oldPwd = entity.getOldPwd();
|
||||||
|
String language = entity.getLanguage();
|
||||||
|
|
||||||
|
// pwd
|
||||||
|
if (T.StrUtil.isAllNotEmpty(pwd, oldPwd)) {
|
||||||
|
// validate
|
||||||
|
String encrypt = T.AesUtil.decrypt(loginUser.getPwd(), Constants.AES_KEY);
|
||||||
|
if (!T.StrUtil.equals(encrypt, oldPwd)) {
|
||||||
|
throw new ASWException(RCode.SYS_USER_OLDPWD_INCORRECT);
|
||||||
|
}
|
||||||
|
// encrypt pwd
|
||||||
|
pwd = T.AesUtil.encrypt(pwd, Constants.AES_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
userService.update(
|
||||||
|
new LambdaUpdateWrapper<SysUserEntity>()
|
||||||
|
.set(SysUserEntity::getName, name)
|
||||||
|
.set(SysUserEntity::getAccessLevel, accessLevel)
|
||||||
|
.set(T.StrUtil.isAllNotEmpty(pwd, oldPwd), SysUserEntity::getPwd, pwd)
|
||||||
|
.set(T.StrUtil.isNotEmpty(language), SysUserEntity::getLanguage, language)
|
||||||
|
.set(SysUserEntity::getUpdateTimestamp, System.currentTimeMillis())
|
||||||
|
.set(SysUserEntity::getUpdateUserId, loginUser.getId())
|
||||||
|
.eq(SysUserEntity::getId, loginUser.getId())
|
||||||
|
);
|
||||||
|
return R.ok().putData("id", loginUser.getId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user