Compare commits
49 Commits
main
...
dev-applic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e675144a6c | ||
|
|
c57ade402f | ||
|
|
f14763512e | ||
|
|
b480734c94 | ||
|
|
1c35979b24 | ||
|
|
68ccb87c76 | ||
|
|
a98566f5d5 | ||
|
|
634166c4b3 | ||
|
|
ecb57f6c6c | ||
|
|
58b38fbe91 | ||
|
|
582856c066 | ||
|
|
76e52d91e9 | ||
|
|
f3d048c240 | ||
|
|
c3d9750bdc | ||
|
|
afb19a4326 | ||
|
|
519b6e1c2d | ||
|
|
e8b6e902c2 | ||
|
|
a32327ad22 | ||
|
|
f7caf6262c | ||
|
|
8932734ef6 | ||
|
|
3265d73dfe | ||
|
|
e88dc879e2 | ||
|
|
11a4000eb2 | ||
|
|
172bd9e890 | ||
|
|
d5f6aef383 | ||
|
|
875eb83d6e | ||
|
|
b6cbe6094f | ||
|
|
9a21b440b0 | ||
|
|
ba87a497bb | ||
|
|
aaff071420 | ||
|
|
a837a160f9 | ||
|
|
af0d0e55ca | ||
|
|
4b53e78124 | ||
|
|
2c8b299735 | ||
|
|
96483dc432 | ||
|
|
d9ec686bc7 | ||
|
|
17328600aa | ||
|
|
6b78f8e61a | ||
|
|
b5af3de27d | ||
|
|
4a2d7f9adf | ||
|
|
4f8084eaf8 | ||
|
|
5e52c711bc | ||
|
|
c0623e8ca5 | ||
|
|
da051af99f | ||
|
|
79146845b9 | ||
|
|
5a4c15b00a | ||
|
|
9e5709d1f1 | ||
|
|
e85811b805 | ||
|
|
58431f9053 |
82
.gitlab-ci.yml
Normal file
82
.gitlab-ci.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
# 定义全局docker镜像
|
||||
image: git.mesalab.cn:7443/nezha/nz-build-env:1.6
|
||||
# 定义全局变量
|
||||
variables:
|
||||
MINIO_HOST: 'http://192.168.40.48:2020/'
|
||||
MINIO_USER: 'admin'
|
||||
MINIO_PWD: "Nezha@02!"
|
||||
MAVEN_REPO: "/etc/maven/repository/"
|
||||
# mariadb 数据库定义(非必须)
|
||||
MYSQL_DATABASE: "test"
|
||||
# mariadb 密码配置(必须),注意变量名是 MYSQL_ROOT_PASSWORD
|
||||
MYSQL_ROOT_PASSWORD: '111111'
|
||||
# 定义全局依赖的docker服务,即 这条流水线 pipeline 中的任务都用这里的服务
|
||||
services:
|
||||
- mariadb:10.2.14
|
||||
# 开始执行脚本前所需执行脚本
|
||||
before_script:
|
||||
- echo "begin ci"
|
||||
# 脚本执行完后的钩子,执行所需脚本
|
||||
after_script:
|
||||
- echo "end ci"
|
||||
# 该ci pipeline适合的场景,按照定义的顺序执行任务
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
# paths主要是来指定需要被缓存的文件路径,需要特别指出的是这里的 paths 是相对路径,是相对于gitlab中项目目录的路径,也就是说被缓存的文件都是在项目目录之内的
|
||||
# maven setting /usr/share/maven/conf/settings.xml
|
||||
cache:
|
||||
paths:
|
||||
- $MAVEN_REPO
|
||||
|
||||
# 定义的任务
|
||||
build_rpm:
|
||||
stage: build
|
||||
# 所需执行的脚本
|
||||
script:
|
||||
- env | sort
|
||||
- pwd
|
||||
- export FILE_NAME=$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA.tar.gz
|
||||
- mvn clean install -Dmaven.test.skip=true
|
||||
- cd ./target
|
||||
- tar -zcvf $FILE_NAME asw-controller.jar
|
||||
# 将 文件 上传到 minio
|
||||
- mc alias set asw $MINIO_HOST $MINIO_USER $MINIO_PWD
|
||||
- mc cp $FILE_NAME asw/release/asw-controller/$FILE_NAME
|
||||
- cd ../
|
||||
# 在哪个分支上可用
|
||||
only:
|
||||
- /^rel-.*$/i
|
||||
# 指定哪个ci runner跑该工作
|
||||
tags:
|
||||
- asw
|
||||
|
||||
# 定义的任务
|
||||
dev_build:
|
||||
stage: test
|
||||
# 所需执行的脚本
|
||||
script:
|
||||
- env | sort
|
||||
- pwd
|
||||
- export FILE_NAME=$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA.tar.gz
|
||||
- mvn clean install -Dmaven.test.skip=true
|
||||
- cd ./target
|
||||
# - "git log -100 --pretty=format:'%ad : %s' > git-log.html"
|
||||
# - tar -zcvf $FILE_NAME asw-controller.jar git-log.html
|
||||
- tar -zcvf $FILE_NAME asw-controller.jar
|
||||
- md5sum $FILE_NAME > $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-latest.tar.gz.md5sum.txt
|
||||
# 将 文件 上传到 minio
|
||||
- mc alias set asw $MINIO_HOST $MINIO_USER $MINIO_PWD
|
||||
- mc cp $FILE_NAME asw/ci-cd/asw-controller/$FILE_NAME
|
||||
- mc cp $FILE_NAME asw/ci-cd/asw-controller/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-latest.tar.gz
|
||||
- mc cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-latest.tar.gz.md5sum.txt asw/ci-cd/asw-controller/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-latest.tar.gz.md5sum.txt
|
||||
- cd ../
|
||||
# 在哪个分支上可用
|
||||
only:
|
||||
- /^dev-.*$/i
|
||||
# 指定不执行的标签
|
||||
except:
|
||||
- schedules
|
||||
# 指定哪个ci runner跑该工作
|
||||
tags:
|
||||
- asw
|
||||
36
pom.xml
36
pom.xml
@@ -79,6 +79,14 @@
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.37.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 jwt -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
<version>1.37.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
@@ -143,6 +151,34 @@
|
||||
<artifactId>simplemagic</artifactId>
|
||||
<version>1.16</version>
|
||||
</dependency>
|
||||
|
||||
<!--Feign client支持-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<version>3.1.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.51</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--opensearch-->
|
||||
<dependency>
|
||||
<groupId>org.opensearch.client</groupId>
|
||||
<artifactId>opensearch-java</artifactId>
|
||||
<version>2.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensearch.client</groupId>
|
||||
<artifactId>opensearch-rest-client</artifactId>
|
||||
<version>2.12.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class GUIHistoryRouterFilter extends OncePerRequestFilter {
|
||||
|
||||
@Value("${router.prefixes:/static/,/api/}")
|
||||
private String pathPrefixes;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
public GUIHistoryRouterFilter(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
List<String> prefixes = Arrays.asList(pathPrefixes.split(","));
|
||||
String path = request.getRequestURI();
|
||||
boolean matches = prefixes.stream().anyMatch(path::startsWith);
|
||||
|
||||
if (!matches) {
|
||||
// If the path does not start with any of the specified prefixes, return index.html
|
||||
Resource resource = resourceLoader.getResource("file:./public/index.html");
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
Files.copy(resource.getFile().toPath(), response.getOutputStream());
|
||||
return;
|
||||
}
|
||||
// If the path matches any of the prefixes, continue the filter chain
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
122
src/main/java/net/geedge/asw/common/config/I18nConfig.java
Normal file
122
src/main/java/net/geedge/asw/common/config/I18nConfig.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import net.geedge.asw.common.util.Constants;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.sys.entity.SysI18nEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysI18nService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.support.AbstractMessageSource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class I18nConfig extends AbstractMessageSource implements ResourceLoaderAware {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private ISysI18nService sysI18nService;
|
||||
|
||||
/**
|
||||
* 国际化缓存
|
||||
*/
|
||||
public static final Map<String, Map<String, String>> I18N_CACHE = new HashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新将数据库中的国际化配置加载
|
||||
*/
|
||||
public void reload() {
|
||||
I18N_CACHE.clear();
|
||||
}
|
||||
|
||||
|
||||
protected ResourceLoader resourceLoader;
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = (resourceLoader == null ? new DefaultResourceLoader() : resourceLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
String msg = this.getSourceFromCache(code, locale);
|
||||
MessageFormat messageFormat = new MessageFormat(msg, locale);
|
||||
return messageFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
return this.getSourceFromCache(code, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中取出国际化配置对应的数据 或者从父级获取
|
||||
*
|
||||
* @param code
|
||||
* @param locale
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public String getSourceFromCache(String code, Locale locale, Object... param) {
|
||||
String language = locale.getLanguage();
|
||||
if (T.ObjectUtil.isEmpty(I18N_CACHE)) {
|
||||
this.loadAllMessageResourcesFromDB();
|
||||
}
|
||||
Map<String, String> props = I18N_CACHE.get(language);
|
||||
if (null != props && props.containsKey(code)) {
|
||||
String msg = props.get(code);
|
||||
if (T.ObjectUtil.isEmpty(param)) {
|
||||
return msg;
|
||||
}
|
||||
return MessageFormat.format(msg, param);
|
||||
} else {
|
||||
try {
|
||||
if (null != this.getParentMessageSource()) {
|
||||
return this.getParentMessageSource().getMessage(code, param, locale);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据库中获取所有国际化配置
|
||||
*/
|
||||
public void loadAllMessageResourcesFromDB() {
|
||||
List<SysI18nEntity> list = sysI18nService.list();
|
||||
if (T.CollUtil.isNotEmpty(list)) {
|
||||
try {
|
||||
for (String lang : Constants.LANG_LIST) {
|
||||
Map<String, String> langMap = I18N_CACHE.get(lang);
|
||||
langMap = T.ObjectUtil.defaultIfNull(langMap, new HashMap<>());
|
||||
I18N_CACHE.put(lang, langMap);
|
||||
|
||||
List<SysI18nEntity> dataList = list.stream().filter(pojo -> T.StrUtil.equals(lang, pojo.getLang())).collect(Collectors.toList());
|
||||
for (SysI18nEntity entity : dataList) {
|
||||
langMap.put(entity.getCode(), entity.getValue());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/main/java/net/geedge/asw/common/config/LocaleConfig.java
Normal file
66
src/main/java/net/geedge/asw/common/config/LocaleConfig.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class LocaleConfig implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
SessionLocaleResolver slr = new SessionLocaleResolver();
|
||||
// 默认语言
|
||||
slr.setDefaultLocale(Locale.of("en"));
|
||||
return slr;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocaleChangeInterceptor localeChangeInterceptor() {
|
||||
MyI18nInterceptor lci = new MyI18nInterceptor();
|
||||
// 参数名
|
||||
lci.setParamName("Language");
|
||||
return lci;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MyI18nInterceptor extends LocaleChangeInterceptor {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
try {
|
||||
String language = request.getHeader(getParamName());
|
||||
if (T.ObjectUtil.isNotEmpty(language)) {
|
||||
Locale locale = parseLocaleValue(language);
|
||||
LocaleContextHolder.setLocale(locale);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e, "[preHandle] [error]");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,23 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.jwt.SaJwtTemplate;
|
||||
import cn.dev33.satoken.jwt.SaJwtUtil;
|
||||
import cn.dev33.satoken.jwt.StpLogicJwtForStateless;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
@@ -38,6 +44,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
config.setTokenStyle("simple-uuid"); // token 风格
|
||||
config.setIsLog(false); // 是否输出操作日志
|
||||
config.setIsPrint(false);
|
||||
// jwt秘钥
|
||||
config.setJwtSecretKey("ypCLARItfzxvdVqRwPcwIasdgAkhoubj");
|
||||
// config.setIsReadCookie(false);
|
||||
}
|
||||
|
||||
@@ -47,7 +55,32 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
||||
registry.addInterceptor(new SaInterceptor(handler -> {
|
||||
SaRouter.match("/file/**").notMatch("/file/content/*").check(r -> StpUtil.checkLogin());
|
||||
SaRouter.match("/sys/**").notMatch("/sys/login").check(r -> StpUtil.checkLogin());
|
||||
SaRouter.match("/api/v1/**").notMatch("/api/v1/login").check(r -> StpUtil.checkLogin());
|
||||
})).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StpLogic getStpLogicJwt() {
|
||||
// Sa-Token 整合 jwt (Stateless 无状态模式)
|
||||
return new StpLogicJwtForStateless();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 SaJwtUtil 生成 token 的算法
|
||||
*/
|
||||
@PostConstruct
|
||||
public void setSaJwtTemplate() {
|
||||
SaJwtUtil.setSaJwtTemplate(new SaJwtTemplate() {
|
||||
@Override
|
||||
public String generateToken(JWT jwt, String keyt) {
|
||||
// header
|
||||
jwt.setHeader("alg", "HS256");
|
||||
jwt.setHeader("typ", "JWT");
|
||||
|
||||
// payload
|
||||
jwt.setPayload("iss", "net.geedge.asw");
|
||||
return super.generateToken(jwt, keyt);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Spring Context 工具类
|
||||
*/
|
||||
@Component
|
||||
public class SpringContextUtils implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
SpringContextUtils.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public static Object getBean(String name) {
|
||||
return applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
return applicationContext.getBean(requiredType);
|
||||
}
|
||||
|
||||
public static String getProperty(String key, String defaultValue) {
|
||||
return applicationContext.getEnvironment().getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
public static <T> T getBean(String name, Class<T> requiredType) {
|
||||
return applicationContext.getBean(name, requiredType);
|
||||
}
|
||||
|
||||
public static Class<? extends Object> getType(String name) {
|
||||
return applicationContext.getType(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
package net.geedge.asw.common.config.exception;
|
||||
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.hutool.log.Log;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
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.sys.service.ISysI18nService;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
@@ -22,6 +24,9 @@ public class ASWExceptionHandler {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private ISysI18nService sysI18nService;
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
@@ -29,7 +34,19 @@ public class ASWExceptionHandler {
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
public R handleDHException(ASWException e, HttpServletRequest request) {
|
||||
log.warn(e, "Request uri: {}", request.getRequestURI());
|
||||
return R.error(e.getCode(), e.getMsg());
|
||||
R r = new R();
|
||||
r.put("code", e.getCode());
|
||||
String msg = "";
|
||||
// by code
|
||||
if (T.ObjectUtil.isNotEmpty(e.getCode())) {
|
||||
msg = sysI18nService.queryValueByName(T.StrUtil.toString(e.getCode()), e.getParam());
|
||||
}
|
||||
if (T.StrUtil.isEmpty(msg) && (T.ObjectUtil.isEmpty(e.getRCode()) || T.ObjectUtil.equals(msg, e.getRCode().toString()))) {
|
||||
r.put("msg", e.getMsg());
|
||||
} else {
|
||||
r.put("msg", msg);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +66,8 @@ public class ASWExceptionHandler {
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
|
||||
log.error(e, "Request uri: {}", request.getRequestURI());
|
||||
return R.error(RCode.SYS_DUPLICATE_RECORD);
|
||||
String msg = sysI18nService.queryValueByName(RCode.SYS_DUPLICATE_RECORD.getCode().toString());
|
||||
return R.error(RCode.SYS_DUPLICATE_RECORD.getCode(), msg);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
|
||||
@@ -12,12 +12,14 @@ public class ASWException extends RuntimeException {
|
||||
private String msg = RCode.ERROR.getMsg();
|
||||
private int code = RCode.ERROR.getCode();
|
||||
private Object[] param = new Object[] {};
|
||||
private RCode rCode;
|
||||
|
||||
public ASWException(RCode rCode) {
|
||||
super(rCode.getMsg());
|
||||
this.code = rCode.getCode();
|
||||
this.msg = rCode.getMsg();
|
||||
this.param = rCode.getParam();
|
||||
this.rCode = rCode;
|
||||
}
|
||||
|
||||
public ASWException(String msg) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.geedge.asw.common.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class Constants {
|
||||
|
||||
@@ -14,6 +15,15 @@ public class Constants {
|
||||
*/
|
||||
public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp";
|
||||
|
||||
/**
|
||||
* 国际化语言列表
|
||||
*/
|
||||
public static final List<String> LANG_LIST = T.ListUtil.of("en", "zh");
|
||||
|
||||
|
||||
/**
|
||||
* 工作空间可见性列表
|
||||
*/
|
||||
public static final List<String> VISIBILITY_LIST = T.ListUtil.of("public", "private");
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.text.MessageFormat;
|
||||
public enum RCode {
|
||||
|
||||
/**
|
||||
* 10**** : 系统认证 或 通用错误提示 20**** : screen module
|
||||
* 10**** : 系统认证 或 通用错误提示 20**** : sys module
|
||||
*/
|
||||
|
||||
ERROR(999, "error"), // 通用错误/未知错误
|
||||
@@ -18,27 +18,56 @@ public enum RCode {
|
||||
PARAM_CANNOT_EMPTY(100006, "parameter cannot be empty"), // parameter 不能为空
|
||||
USER_NO_LOGIN(100007, "user not login"), // 用户未登录
|
||||
SYS_RECORD_NOT_FOUND(100008, "record not found"),// 未找到记录
|
||||
USER_ID_CANNOT_EMPTY(100009, "user id cannot be empty"),// 用户 ID 不能为空
|
||||
ROLE_ID_CANNOT_EMPTY(100010, "role id cannot be empty"),// 权限 ID 不能为空
|
||||
USER_NOT_EXIST(100011, "user does not exist"),
|
||||
ROLE_NOT_EXIST(100012, "role does not exist"),
|
||||
|
||||
|
||||
SCREEN_ID_CANNOT_EMPTY(200001, "id cannot be empty"),
|
||||
// Application
|
||||
APP_ID_CANNOT_EMPTY(201001, "application id cannot be empty"),
|
||||
APP_NAME_CANNOT_EMPTY(201002, "application name cannot be empty"),
|
||||
APP_LONGNAME_CANNOT_EMPTY(201003, "application longName cannot be empty"),
|
||||
APP_PROPERTIES_CANNOT_EMPTY(201004, "application properties cannot be empty"),
|
||||
APP_SURROGATES_CANNOT_EMPTY(201005, "application surrogates cannot be empty"),
|
||||
APP_DESCRIPTION_CANNOT_EMPTY(201006, "application description cannot be empty"),
|
||||
APP_DUPLICATE_RECORD(201007, "application duplicate record"),
|
||||
APP_NOT_EXIST(201008, "application does not exist"),
|
||||
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"),
|
||||
|
||||
SCREE_DATASOURCE_DEFAULT_CANNOT_BE_DELETE(300001,"The default data source cannot be deleted."),
|
||||
SCREE_DATASOURCE_REPEAT(300002,"Screen datasource name duplicate"),
|
||||
|
||||
/**
|
||||
* import
|
||||
*/
|
||||
EXCELFILE_TYPE_ERROR(400001, "The type can only be xlsx, json, csv"),
|
||||
EXCELFILE_PARSE_ERROR(400002, "Import file resolution failed"),
|
||||
EXCELFILE_HEADER_TEMPLATE_ERROR(400003,"The header row of the import template is inconsistent with the system template"),
|
||||
EXCELFILE_HEADER_LANGUAGE_ERROR(400004, "Language must be en, zh or ru"),
|
||||
EXCELFILE_IMPORT_FILE_ISNULL(400005, "Import file is null"),
|
||||
EXCELFILE_HEADER_LANGUAGE_ISNULL(400006, "Language can not be empty"),
|
||||
EXCELFILE_IMPORT_ERROR(400007, "File import error"),
|
||||
EXCELFILE_SCHEDULE_TASK_IS_NULL(400008, "Schedule task can not be empty"),
|
||||
EXCELFILE_SCHEDULE_CRON_IS_NULL(400009, "Schedule cron can not be empty"),
|
||||
EXCELFILE_SCHEDULE_ENABLE_IS_NULL(400010, "Schedule enable can not be empty"),
|
||||
EXCELFILE_SCHEDULE_SCRIPT_IS_NULL(400011, "Schedule script can not be empty"),
|
||||
|
||||
// Package
|
||||
PACKAGE_ID_CANNOT_EMPTY(202001, "package id cannot be empty"),
|
||||
PACKAGE_DESCRIPTION_CANNOT_EMPTY(202002, "package description cannot be empty"),
|
||||
|
||||
|
||||
// Runner
|
||||
RUNNER_ID_CANNOT_EMPTY(301001, "runner id cannot be empty"),
|
||||
|
||||
|
||||
// Playbook
|
||||
PLAYBOOK_ID_CANNOT_EMPTY(302001, "playbook id cannot be empty"),
|
||||
|
||||
|
||||
// Workspace
|
||||
WORKSPACE_ID_CANNOT_EMPTY(401001, "workspace id cannot be empty"),
|
||||
WORKSPACE_NAME_CANNOT_EMPTY(401002, "workspace name cannot be empty"),
|
||||
WORKSPACE_VISIBILITY_CANNOT_EMPTY(401003, "workspace visibility cannot be empty"),
|
||||
WORKSPACE_USER_CANNOT_EMPTY(401004, "workspace user cannot be empty"),
|
||||
WORKSPACE_ALREADY_EXISTS(401005, "workspace already exists"),
|
||||
WORKSPACE_MEMBER_CANNOT_EMPTY(401006, "workspace member cannot be empty"),
|
||||
WORKSPACE_CANNOT_DELETE(401007, "Built-in workspace cannot be deleted"),
|
||||
WORKSPACE_VISIBILITY_ERROR(401008, "workspace visibility error"),
|
||||
WORKSPACE_BUILT_IN(401009, "Built-in workspace cannot be update"),
|
||||
|
||||
//PCAP
|
||||
PCAP_UPLOAD_WEB_SHARK_ERROR(501001, "web shark upload pcap error"),
|
||||
|
||||
|
||||
SUCCESS(200, "success"); // 成功
|
||||
|
||||
@@ -1,27 +1,9 @@
|
||||
package net.geedge.asw.common.util;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Robot;
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
@@ -29,10 +11,23 @@ import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.ref.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.Socket;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class T {
|
||||
|
||||
@@ -315,6 +310,27 @@ public class T {
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public static class PageUtil extends cn.hutool.core.util.PageUtil {
|
||||
public static final Integer DEFAULT_PAGENO = 1;
|
||||
public static final Integer DEFAULT_PAGESIZE = 20;
|
||||
|
||||
public static Page getPage(Map<String, Object> params) {
|
||||
// 分页参数
|
||||
Integer pageNo = T.MapUtil.getInt(params, "current", DEFAULT_PAGENO);
|
||||
Integer pageSize = T.MapUtil.getInt(params, "size", DEFAULT_PAGESIZE);
|
||||
if (pageSize == -1) {
|
||||
pageNo = 0;
|
||||
pageSize = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
Page page = Page.of(pageNo, pageSize);
|
||||
|
||||
String orderBy = T.MapUtil.getStr(params, "orderBy");
|
||||
if (T.StrUtil.isNotEmpty(orderBy)) {
|
||||
page.addOrder(T.PageUtil.decodeOrderByStr(orderBy));
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
public static OrderItem decodeOrderByStr(String orderBy) {
|
||||
if (cn.hutool.core.util.StrUtil.isBlank(orderBy)) {
|
||||
return null;
|
||||
@@ -1526,4 +1542,37 @@ public class T {
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取项目中各种路径
|
||||
*
|
||||
* @author ThinkPad
|
||||
*/
|
||||
public static class WebPathUtil {
|
||||
private static final Log log = Log.get();
|
||||
|
||||
/**
|
||||
* 如果已打成jar包,则返回jar包所在目录
|
||||
* 如果未打成jar,则返回target所在目录
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getClassPath() {
|
||||
try {
|
||||
// 项目的编译文件的根目录
|
||||
String path = URLDecoder.decode(System.getProperty("user.dir"), "utf-8");
|
||||
log.debug("root path:{}", path);
|
||||
return path;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRootPath() {
|
||||
File file = T.FileUtil.file(WebPathUtil.getClassPath());
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -387,6 +387,13 @@ public class VerifyUtil {
|
||||
return this;
|
||||
}
|
||||
|
||||
public VerifyUtil json(RCode code) {
|
||||
if (!T.JSONUtil.isTypeJSON(T.StrUtil.toStringOrNull(value))) {
|
||||
throw ASWException.builder().rcode(code).build();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多参数校验,不能同时为空
|
||||
*
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package net.geedge.asw.module.app.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.entity.ApplicationAttachmentEntity;
|
||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||
import net.geedge.asw.module.app.entity.ApplicationNoteEntity;
|
||||
import net.geedge.asw.module.app.entity.ApplicationSignatureEntity;
|
||||
import net.geedge.asw.module.app.service.ApplicationAttachmentService;
|
||||
import net.geedge.asw.module.app.service.ApplicationNoteService;
|
||||
import net.geedge.asw.module.app.service.ApplicationSignatureService;
|
||||
import net.geedge.asw.module.app.service.IApplicationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/application")
|
||||
public class ApplicationController {
|
||||
|
||||
@Autowired
|
||||
private IApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationSignatureService signatureService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationNoteService noteService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationAttachmentService attachmentService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id, String workspaceId) {
|
||||
T.VerifyUtil.is(workspaceId).notNull();
|
||||
ApplicationEntity entity = applicationService.detail(id, workspaceId);
|
||||
if (T.ObjectUtil.isNull(entity)) {
|
||||
throw new ASWException(RCode.APP_NOT_EXIST);
|
||||
}
|
||||
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 = applicationService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R add(@RequestBody ApplicationEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getName()).notEmpty(RCode.APP_NAME_CANNOT_EMPTY)
|
||||
//.and(entity.getSignature()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
||||
//.and(entity.getNote()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
|
||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
ApplicationEntity applicationEntity = applicationService.saveApplication(entity);
|
||||
return R.ok().putData("id", applicationEntity.getId());
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R update(@RequestBody ApplicationEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
|
||||
//.and(entity.getSignature()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
|
||||
//.and(entity.getNote()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
|
||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
ApplicationEntity applicationEntity = applicationService.updateApplication(entity);
|
||||
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
|
||||
public R delete(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
applicationService.removeApplication(T.ListUtil.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{applicationId}/attachment")
|
||||
public R queryAttachment(@PathVariable String applicationId) {
|
||||
T.VerifyUtil.is(applicationId).notNull();
|
||||
|
||||
List<ApplicationAttachmentEntity> list = attachmentService.list(new LambdaQueryWrapper<ApplicationAttachmentEntity>().eq(ApplicationAttachmentEntity::getApplicationId, applicationId));
|
||||
return R.ok().putData("records", list);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/{applicationId}/attachment")
|
||||
public R uploadAttachment(@PathVariable String applicationId, @RequestParam("files") List<MultipartFile> fileList) {
|
||||
|
||||
List<ApplicationAttachmentEntity> recordList = T.ListUtil.list(true);
|
||||
for (int i = 0; i < fileList.size(); i++) {
|
||||
MultipartFile file = fileList.get(i);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{applicationId}/signature")
|
||||
public R querySignature(@PathVariable String applicationId) {
|
||||
T.VerifyUtil.is(applicationId).notNull();
|
||||
List<ApplicationSignatureEntity> signatureList = signatureService.queryList(applicationId);
|
||||
return R.ok().putData("records", signatureList);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/explore")
|
||||
public R explore(@RequestParam String workspaceId, @RequestParam String pcapIds) {
|
||||
String discoverUrl = applicationService.generateKibanaDiscoverUrl(workspaceId, pcapIds);
|
||||
return R.ok().putData("url", discoverUrl);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.geedge.asw.module.app.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.entity.PackageEntity;
|
||||
import net.geedge.asw.module.app.service.IPackageService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/package")
|
||||
public class PackageController {
|
||||
|
||||
@Autowired
|
||||
private IPackageService packageService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
PackageEntity entity = packageService.getById(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 = packageService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R add(@RequestBody PackageEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.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.savePackage(entity);
|
||||
return R.ok().putData("id", pkgEntity.getId());
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
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) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
packageService.removePackage(T.ListUtil.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.geedge.asw.module.app.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||
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.Map;
|
||||
|
||||
@Mapper
|
||||
public interface ApplicationDao extends BaseMapper<ApplicationEntity>{
|
||||
|
||||
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,10 @@
|
||||
package net.geedge.asw.module.app.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
@Mapper
|
||||
public interface ApplicationLogDao extends BaseMapper<ApplicationLogEntity> {
|
||||
}
|
||||
@@ -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.ApplicationNoteEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
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);
|
||||
}
|
||||
16
src/main/java/net/geedge/asw/module/app/dao/PackageDao.java
Normal file
16
src/main/java/net/geedge/asw/module/app/dao/PackageDao.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package net.geedge.asw.module.app.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface PackageDao extends BaseMapper<PackageEntity>{
|
||||
|
||||
List<PackageEntity> queryList(Page page, Map<String, 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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@TableName("application")
|
||||
public class ApplicationEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String tags;
|
||||
|
||||
private String packageName;
|
||||
|
||||
private String website;
|
||||
|
||||
private String provider;
|
||||
|
||||
private String status;
|
||||
|
||||
private String description;
|
||||
|
||||
private Long createTimestamp;
|
||||
|
||||
private Long updateTimestamp;
|
||||
|
||||
private String createUserId;
|
||||
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@TableName("application_log")
|
||||
public class ApplicationLogEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String tags;
|
||||
|
||||
private String packageName;
|
||||
|
||||
private String website;
|
||||
|
||||
private String provider;
|
||||
|
||||
private String status;
|
||||
|
||||
private String description;
|
||||
|
||||
private Long createTimestamp;
|
||||
|
||||
private Long updateTimestamp;
|
||||
|
||||
private String createUserId;
|
||||
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -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_note")
|
||||
public class ApplicationNoteEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
private String applicationId;
|
||||
|
||||
private String content;
|
||||
|
||||
private Long createTimestamp;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
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;
|
||||
|
||||
@Data
|
||||
@TableName("package")
|
||||
public class PackageEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String logo;
|
||||
private String description;
|
||||
private String platform;
|
||||
private String version;
|
||||
private String identifier;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String workbookId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.geedge.asw.module.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
public interface ApplicationAttachmentService extends IService<ApplicationAttachmentEntity>{
|
||||
|
||||
ApplicationAttachmentEntity saveAttachment(Resource fileResource, String applicationId);
|
||||
|
||||
void removedAttachment(String applicationId, String ids);
|
||||
}
|
||||
@@ -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 ApplicationNoteService extends IService<ApplicationNoteEntity>{
|
||||
|
||||
void saveNote(ApplicationNoteEntity note, String applicationId);
|
||||
}
|
||||
@@ -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.ApplicationSignatureEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApplicationSignatureService 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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.geedge.asw.module.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
||||
|
||||
public interface IApplicationLogService extends IService<ApplicationLogEntity> {
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.geedge.asw.module.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IApplicationService extends IService<ApplicationEntity>{
|
||||
|
||||
ApplicationEntity detail(String id, String workspaceId);
|
||||
|
||||
Page queryList(Map<String, Object> params);
|
||||
|
||||
ApplicationEntity saveApplication(ApplicationEntity entity);
|
||||
|
||||
ApplicationEntity updateApplication(ApplicationEntity entity);
|
||||
|
||||
ApplicationEntity updateBasic(ApplicationEntity entity);
|
||||
|
||||
void removeApplication(List<String> ids);
|
||||
|
||||
String generateKibanaDiscoverUrl(String workspaceId, String pcapIds);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.geedge.asw.module.app.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IPackageService extends IService<PackageEntity>{
|
||||
|
||||
Page queryList(Map<String, Object> params);
|
||||
|
||||
PackageEntity savePackage(PackageEntity entity);
|
||||
|
||||
PackageEntity updatePackage(PackageEntity entity);
|
||||
|
||||
void removePackage(List<String> ids);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
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 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.ApplicationAttachmentService;
|
||||
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.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 ApplicationAttachmentService {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.geedge.asw.module.app.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.module.app.dao.ApplicationLogDao;
|
||||
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
|
||||
import net.geedge.asw.module.app.service.IApplicationLogService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
@Service
|
||||
public class ApplicationLogServiceImpl extends ServiceImpl<ApplicationLogDao, ApplicationLogEntity> implements IApplicationLogService {
|
||||
|
||||
}
|
||||
@@ -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.ApplicationNoteService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class ApplicationNoteServiceImpl extends ServiceImpl<ApplicationNoteDao, ApplicationNoteEntity> implements ApplicationNoteService {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
package net.geedge.asw.module.app.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.net.url.UrlBuilder;
|
||||
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.extension.plugins.pagination.Page;
|
||||
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.RCode;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.app.dao.ApplicationDao;
|
||||
import net.geedge.asw.module.app.entity.*;
|
||||
import net.geedge.asw.module.app.service.*;
|
||||
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.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.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Value("${kibana.url:127.0.0.1:5601}")
|
||||
private String kibanaUrl;
|
||||
|
||||
@Autowired
|
||||
private IApplicationLogService applicationLogService;
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceService workspaceService;
|
||||
|
||||
@Autowired
|
||||
private IPcapService pcapService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationSignatureService signatureService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationNoteService noteService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationAttachmentService attachmentService;
|
||||
|
||||
@Resource
|
||||
private KibanaClient kibanaClient;
|
||||
|
||||
@Override
|
||||
public ApplicationEntity detail(String id, String workspaceId) {
|
||||
ApplicationEntity app = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
||||
.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()));
|
||||
app.setAttatchments(attachmentEntityList);
|
||||
|
||||
SysUserEntity createUser = userService.getById(app.getCreateUserId());
|
||||
SysUserEntity updateUser = userService.getById(app.getUpdateUserId());
|
||||
app.setCreateUser(createUser);
|
||||
app.setUpdateUser(updateUser);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
List<ApplicationEntity> packageList = this.getBaseMapper().queryList(page, params);
|
||||
page.setRecords(packageList);
|
||||
return page;
|
||||
}
|
||||
|
||||
private void validateParam(ApplicationEntity entity, boolean isUpdate) {
|
||||
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
|
||||
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
|
||||
.eq(ApplicationEntity::getName, entity.getName()));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// 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("{}");
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApplicationEntity saveApplication(ApplicationEntity entity) {
|
||||
|
||||
this.validateParam(entity, false);
|
||||
|
||||
// save
|
||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApplicationEntity updateApplication(ApplicationEntity entity) {
|
||||
|
||||
this.validateParam(entity, true);
|
||||
|
||||
ApplicationEntity one = this.getById(entity.getId());
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setOpVersion(one.getOpVersion() + 1);
|
||||
|
||||
// update
|
||||
this.updateById(entity);
|
||||
|
||||
// save log
|
||||
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;
|
||||
}
|
||||
|
||||
private void saveApplicationToLog(ApplicationEntity one) {
|
||||
ApplicationLogEntity applicationLogEntity = T.BeanUtil.toBean(one, ApplicationLogEntity.class);
|
||||
applicationLogEntity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
applicationLogEntity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
applicationLogEntity.setCreateTimestamp(System.currentTimeMillis());
|
||||
applicationLogEntity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||
applicationLogService.save(applicationLogEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeApplication(List<String> ids) {
|
||||
// remove
|
||||
this.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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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 ApplicationEntity updateBasic(ApplicationEntity entity) {
|
||||
|
||||
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("{}");
|
||||
}
|
||||
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setOpVersion(one.getOpVersion() + 1);
|
||||
|
||||
this.saveApplicationToLog(one);
|
||||
this.updateById(entity);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
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.ApplicationSignatureService;
|
||||
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 ApplicationSignatureService {
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveSignature(ApplicationSignatureEntity signature, String applicationId) {
|
||||
// query last note
|
||||
ApplicationSignatureEntity signatureLast = this.getOne(new LambdaQueryWrapper<ApplicationSignatureEntity>()
|
||||
.eq(ApplicationSignatureEntity::getApplicationId, applicationId)
|
||||
.orderByDesc(ApplicationSignatureEntity::getOpVersion)
|
||||
.last("limit 1"));
|
||||
|
||||
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.getOne(new LambdaQueryWrapper<ApplicationSignatureEntity>()
|
||||
.eq(ApplicationSignatureEntity::getApplicationId, applicationId)
|
||||
.orderByDesc(ApplicationSignatureEntity::getOpVersion)
|
||||
.last("limit 1"));
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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.plugins.pagination.Page;
|
||||
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.PackageDao;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
import net.geedge.asw.module.app.service.IPackageService;
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> implements IPackageService {
|
||||
|
||||
@Autowired
|
||||
private IWorkbookResourceService workbookResourceService;
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
List<PackageEntity> packageList = this.getBaseMapper().queryList(page, params);
|
||||
page.setRecords(packageList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PackageEntity savePackage(PackageEntity entity) {
|
||||
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());
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
|
||||
// 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.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
|
||||
// update
|
||||
this.updateById(entity);
|
||||
|
||||
// workbook resource
|
||||
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.PACKAGE.getValue());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removePackage(List<String> ids) {
|
||||
// remove
|
||||
this.removeBatchByIds(ids);
|
||||
// workbook resource
|
||||
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package net.geedge.asw.module.feign;
|
||||
|
||||
import cn.hutool.core.net.url.UrlBuilder;
|
||||
import cn.hutool.log.Log;
|
||||
import feign.Feign;
|
||||
import feign.form.FormEncoder;
|
||||
import net.geedge.asw.module.feign.client.GeoipClient;
|
||||
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.Fastjson2Encoder;
|
||||
import net.geedge.asw.module.feign.support.Http2Client;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class FeignClientConfiguration {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Value("${zeek.url:127.0.0.1:8086}")
|
||||
private String zeekUrl;
|
||||
|
||||
@Value("${geoip.url:127.0.0.1:8087}")
|
||||
private String geoipUrl;
|
||||
|
||||
@Value("${kibana.url:127.0.0.1:5601}")
|
||||
private String kibanaUrl;
|
||||
|
||||
@Value("${webShark.url:127.0.0.1:8085}")
|
||||
private String websharkurl;
|
||||
|
||||
@Bean("zeekClient")
|
||||
public ZeekClient zeekClient() {
|
||||
String url = UrlBuilder.ofHttp(zeekUrl).toString();
|
||||
log.info("[zeekClient] [url: {}]", url);
|
||||
return Feign.builder()
|
||||
.encoder(new FormEncoder())
|
||||
.decoder(new Fastjson2Decoder())
|
||||
.client(new Http2Client())
|
||||
.target(ZeekClient.class, url);
|
||||
}
|
||||
|
||||
@Bean("geoipClient")
|
||||
public GeoipClient geoipClient() {
|
||||
String url = UrlBuilder.ofHttp(geoipUrl).toString();
|
||||
log.info("[geoipClient] [url: {}]", url);
|
||||
return Feign.builder()
|
||||
.encoder(new Fastjson2Encoder())
|
||||
.decoder(new Fastjson2Decoder())
|
||||
.client(new Http2Client())
|
||||
.target(GeoipClient.class, url);
|
||||
}
|
||||
|
||||
@Bean("kibanaClient")
|
||||
public KibanaClient kibanaClient() {
|
||||
String url = UrlBuilder.ofHttp(kibanaUrl).toString();
|
||||
log.info("[kibanaClient] [url: {}]", url);
|
||||
return Feign.builder()
|
||||
.encoder(new Fastjson2Encoder())
|
||||
.decoder(new Fastjson2Decoder())
|
||||
.client(new Http2Client())
|
||||
.target(KibanaClient.class, url);
|
||||
}
|
||||
|
||||
@Bean("webSharkClient")
|
||||
public WebSharkClient webSharkClient() {
|
||||
String url = UrlBuilder.ofHttp(websharkurl).toString();
|
||||
log.info("[webSharkClient] [url: {}]", url);
|
||||
return Feign.builder()
|
||||
.encoder(new FormEncoder())
|
||||
.decoder(new Fastjson2Decoder())
|
||||
.client(new Http2Client())
|
||||
.target(WebSharkClient.class, url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package net.geedge.asw.module.feign;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.nio.reactor.IOReactorConfig;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.opensearch.client.RestClient;
|
||||
import org.opensearch.client.RestClientBuilder;
|
||||
import org.opensearch.client.json.jackson.JacksonJsonpMapper;
|
||||
import org.opensearch.client.opensearch.OpenSearchClient;
|
||||
import org.opensearch.client.opensearch.core.InfoResponse;
|
||||
import org.opensearch.client.transport.OpenSearchTransport;
|
||||
import org.opensearch.client.transport.rest_client.RestClientTransport;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
@Component
|
||||
public class OpenSearchClientConfiguration {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Value("${opensearch.url:127.0.0.1:7200}")
|
||||
private String hostAndPort;
|
||||
|
||||
@Value("${opensearch.username:admin}")
|
||||
private String username;
|
||||
|
||||
@Value("${opensearch.password:G1egG2U4NrjHRzV}")
|
||||
private String password;
|
||||
|
||||
@Bean("openSearchClient")
|
||||
public OpenSearchClient openSearchClient() {
|
||||
try {
|
||||
if (T.StrUtil.hasEmpty(this.hostAndPort, this.username, this.password)) {
|
||||
throw new IllegalArgumentException("OpenSearchClient init info cannot be empty.");
|
||||
}
|
||||
|
||||
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
|
||||
|
||||
// Setup SSL context to trust all certificates
|
||||
SSLContext sslContext = SSLContextBuilder.create()
|
||||
.loadTrustMaterial((chain, authType) -> true)
|
||||
.build();
|
||||
|
||||
String[] split = this.hostAndPort.split(":");
|
||||
String host = split[0];
|
||||
Integer port = Integer.valueOf(split[1]);
|
||||
SSLContext finalSslContext = sslContext;
|
||||
RestClientBuilder builder = RestClient.builder(
|
||||
new HttpHost(host, port, "https"))
|
||||
.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
|
||||
httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
|
||||
.setSSLContext(finalSslContext)
|
||||
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
|
||||
.setDefaultIOReactorConfig(
|
||||
IOReactorConfig.custom()
|
||||
.setIoThreadCount(1)
|
||||
.build()
|
||||
);
|
||||
return httpAsyncClientBuilder;
|
||||
});
|
||||
|
||||
RestClient restClient = builder.build();
|
||||
OpenSearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
OpenSearchClient client = new OpenSearchClient(transport);
|
||||
|
||||
InfoResponse info = client.info();
|
||||
log.info("[openSearchClient] [url: {}] [{}]", this.hostAndPort, info.version().distribution() + ": " + info.version().number());
|
||||
return client;
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | IOException e) {
|
||||
log.error("[openSearchClient] [error] [url: {}]", this.hostAndPort);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.geedge.asw.module.feign.client;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import feign.Param;
|
||||
import feign.RequestLine;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
@FeignClient(name = "geoipClient")
|
||||
public interface GeoipClient {
|
||||
|
||||
@RequestLine("GET /geoip?ips={ip}")
|
||||
JSONArray geoip(@Param("ip") String ipAddress);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
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;
|
||||
|
||||
@FeignClient(name = "kibanaClient")
|
||||
@Headers("Authorization: Bearer {token}")
|
||||
public interface KibanaClient {
|
||||
|
||||
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type=index-pattern&search_fields=title&search={name}")
|
||||
JSONObject findIndexPattern(@Param("token") String token, @Param("name") String name);
|
||||
|
||||
@Headers({
|
||||
"Content-Type: application/json",
|
||||
"osd-xsrf: true"
|
||||
})
|
||||
@RequestLine("POST /api/saved_objects/index-pattern/{id}")
|
||||
JSONObject saveIndexPattern(@Param("token") String token, @Param("id") String id, JSONObject body);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.geedge.asw.module.feign.client;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import feign.Headers;
|
||||
import feign.Param;
|
||||
import feign.RequestLine;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
@FeignClient(name = "webSharkClient")
|
||||
public interface WebSharkClient {
|
||||
|
||||
@RequestLine("POST /webshark/upload")
|
||||
@Headers("Content-Type: multipart/form-data")
|
||||
JSONObject upload(@Param("fileKey") File file);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.geedge.asw.module.feign.client;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import feign.Headers;
|
||||
import feign.Param;
|
||||
import feign.RequestLine;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@FeignClient(name = "zeekClient")
|
||||
public interface ZeekClient {
|
||||
|
||||
@RequestLine("POST /upload")
|
||||
@Headers("Content-Type: multipart/form-data")
|
||||
JSONArray parser(@Param("pcap") File file);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2024 The Feign Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package net.geedge.asw.module.feign.support;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONException;
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
import feign.codec.Decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import static feign.Util.ensureClosed;
|
||||
|
||||
/**
|
||||
* @author changjin wei(魏昌进)
|
||||
*/
|
||||
public class Fastjson2Decoder implements Decoder {
|
||||
|
||||
private final JSONReader.Feature[] features;
|
||||
|
||||
public Fastjson2Decoder() {
|
||||
this(new JSONReader.Feature[0]);
|
||||
}
|
||||
|
||||
public Fastjson2Decoder(JSONReader.Feature[] features) {
|
||||
this.features = features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Response response, Type type) throws IOException, FeignException {
|
||||
if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type);
|
||||
if (response.body() == null) return null;
|
||||
Reader reader = response.body().asReader(response.charset());
|
||||
try {
|
||||
return JSON.parseObject(reader, type, features);
|
||||
} catch (JSONException e) {
|
||||
if (e.getCause() != null && e.getCause() instanceof IOException) {
|
||||
throw IOException.class.cast(e.getCause());
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
ensureClosed(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2024 The Feign Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package net.geedge.asw.module.feign.support;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import feign.RequestTemplate;
|
||||
import feign.Util;
|
||||
import feign.codec.EncodeException;
|
||||
import feign.codec.Encoder;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author changjin wei(魏昌进)
|
||||
*/
|
||||
public class Fastjson2Encoder implements Encoder {
|
||||
|
||||
private final JSONWriter.Feature[] features;
|
||||
|
||||
public Fastjson2Encoder() {
|
||||
this(new JSONWriter.Feature[0]);
|
||||
}
|
||||
|
||||
public Fastjson2Encoder(JSONWriter.Feature[] features) {
|
||||
this.features = features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
|
||||
template.body(JSON.toJSONBytes(object, features), Util.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2012-2024 The Feign Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package net.geedge.asw.module.feign.support;
|
||||
|
||||
import feign.*;
|
||||
import feign.Request.Options;
|
||||
import feign.Request.ProtocolVersion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpClient.Redirect;
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublisher;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpRequest.Builder;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static feign.Util.enumForName;
|
||||
|
||||
public class Http2Client implements Client, AsyncClient<Object> {
|
||||
|
||||
private final HttpClient client;
|
||||
|
||||
private final Map<Integer, SoftReference<HttpClient>> clients = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Creates the new Http2Client using following defaults:
|
||||
* <ul>
|
||||
* <li>Connect Timeout: 10 seconds, as {@link Request.Options#Options()} uses</li>
|
||||
* <li>Follow all 3xx redirects</li>
|
||||
* <li>HTTP 2</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see Request.Options#Options()
|
||||
*/
|
||||
public Http2Client() {
|
||||
this(HttpClient.newBuilder()
|
||||
.followRedirects(Redirect.ALWAYS)
|
||||
.version(Version.HTTP_2)
|
||||
.connectTimeout(Duration.ofMillis(10000))
|
||||
.build());
|
||||
}
|
||||
|
||||
public Http2Client(Options options) {
|
||||
this(newClientBuilder(options)
|
||||
.version(Version.HTTP_2)
|
||||
.build());
|
||||
}
|
||||
|
||||
public Http2Client(HttpClient client) {
|
||||
this.client = Util.checkNotNull(client, "HttpClient must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request, Options options) throws IOException {
|
||||
final HttpRequest httpRequest;
|
||||
try {
|
||||
httpRequest = newRequestBuilder(request, options)
|
||||
.version(client.version())
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IOException("Invalid uri " + request.url(), e);
|
||||
}
|
||||
|
||||
HttpClient clientForRequest = getOrCreateClient(options);
|
||||
HttpResponse<InputStream> httpResponse;
|
||||
try {
|
||||
httpResponse = clientForRequest.send(httpRequest, BodyHandlers.ofInputStream());
|
||||
} catch (final InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
return toFeignResponse(request, httpResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Response> execute(Request request,
|
||||
Options options,
|
||||
Optional<Object> requestContext) {
|
||||
HttpRequest httpRequest;
|
||||
try {
|
||||
httpRequest = newRequestBuilder(request, options).build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException("Invalid uri " + request.url(), e);
|
||||
}
|
||||
|
||||
HttpClient clientForRequest = getOrCreateClient(options);
|
||||
CompletableFuture<HttpResponse<InputStream>> future =
|
||||
clientForRequest.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofInputStream());
|
||||
return future.thenApply(httpResponse -> toFeignResponse(request, httpResponse));
|
||||
}
|
||||
|
||||
protected Response toFeignResponse(Request request, HttpResponse<InputStream> httpResponse) {
|
||||
final OptionalLong length = httpResponse.headers().firstValueAsLong("Content-Length");
|
||||
|
||||
return Response.builder()
|
||||
.protocolVersion(enumForName(ProtocolVersion.class, httpResponse.version()))
|
||||
.body(httpResponse.body(), length.isPresent() ? (int) length.getAsLong() : null)
|
||||
.reason(httpResponse.headers().firstValue("Reason-Phrase").orElse(null))
|
||||
.request(request)
|
||||
.status(httpResponse.statusCode())
|
||||
.headers(castMapCollectType(httpResponse.headers().map()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private HttpClient getOrCreateClient(Options options) {
|
||||
if (doesClientConfigurationDiffer(options)) {
|
||||
// create a new client from the existing one - but with connectTimeout and followRedirect
|
||||
// settings from options
|
||||
final int clientKey = createClientKey(options);
|
||||
|
||||
SoftReference<HttpClient> requestScopedSoftReference = clients.get(clientKey);
|
||||
HttpClient requestScoped =
|
||||
requestScopedSoftReference == null ? null : requestScopedSoftReference.get();
|
||||
|
||||
if (requestScoped == null) {
|
||||
java.net.http.HttpClient.Builder builder = newClientBuilder(options)
|
||||
.sslContext(client.sslContext())
|
||||
.sslParameters(client.sslParameters())
|
||||
.version(client.version());
|
||||
client.authenticator().ifPresent(builder::authenticator);
|
||||
client.cookieHandler().ifPresent(builder::cookieHandler);
|
||||
client.executor().ifPresent(builder::executor);
|
||||
client.proxy().ifPresent(builder::proxy);
|
||||
requestScoped = builder.build();
|
||||
clients.put(clientKey, new SoftReference<>(requestScoped));
|
||||
}
|
||||
return requestScoped;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
private boolean doesClientConfigurationDiffer(Options options) {
|
||||
if ((client.followRedirects() == Redirect.ALWAYS) != options.isFollowRedirects()) {
|
||||
return true;
|
||||
}
|
||||
return client.connectTimeout()
|
||||
.map(timeout -> timeout.toMillis() != options.connectTimeoutMillis())
|
||||
.orElse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates integer key that represents {@link Options} settings based on
|
||||
* {@link Http2Client#doesClientConfigurationDiffer(Options)} method
|
||||
*
|
||||
* @param options value
|
||||
* @return integer key
|
||||
*/
|
||||
public int createClientKey(feign.Request.Options options) {
|
||||
int key = options.connectTimeoutMillis();
|
||||
if (options.isFollowRedirects()) {
|
||||
key |= 1 << 31; // connectTimeoutMillis always positive, so we can use first sign bit for
|
||||
// isFollowRedirects flag
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private static java.net.http.HttpClient.Builder newClientBuilder(Options options) {
|
||||
return HttpClient
|
||||
.newBuilder()
|
||||
.followRedirects(options.isFollowRedirects() ? Redirect.ALWAYS : Redirect.NEVER)
|
||||
.connectTimeout(Duration.ofMillis(options.connectTimeoutMillis()));
|
||||
}
|
||||
|
||||
private Builder newRequestBuilder(Request request, Options options) throws URISyntaxException {
|
||||
URI uri = new URI(request.url());
|
||||
|
||||
final BodyPublisher body;
|
||||
final byte[] data = request.body();
|
||||
if (data == null) {
|
||||
body = BodyPublishers.noBody();
|
||||
} else {
|
||||
body = BodyPublishers.ofByteArray(data);
|
||||
}
|
||||
|
||||
final Builder requestBuilder = HttpRequest.newBuilder()
|
||||
.uri(uri)
|
||||
.timeout(Duration.ofMillis(options.readTimeoutMillis()))
|
||||
.version(client.version());
|
||||
|
||||
final Map<String, Collection<String>> headers = filterRestrictedHeaders(request.headers());
|
||||
if (!headers.isEmpty()) {
|
||||
requestBuilder.headers(asString(headers));
|
||||
}
|
||||
|
||||
return requestBuilder.method(request.httpMethod().toString(), body);
|
||||
}
|
||||
|
||||
/**
|
||||
* There is a bunch o headers that the http2 client do not allow to be set.
|
||||
*
|
||||
* @see jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET
|
||||
*/
|
||||
private static final Set<String> DISALLOWED_HEADERS_SET;
|
||||
|
||||
static {
|
||||
// A case insensitive TreeSet of strings.
|
||||
final TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
|
||||
treeSet.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade"));
|
||||
DISALLOWED_HEADERS_SET = Collections.unmodifiableSet(treeSet);
|
||||
}
|
||||
|
||||
private Map<String, Collection<String>> filterRestrictedHeaders(Map<String, Collection<String>> headers) {
|
||||
final Map<String, Collection<String>> filteredHeaders = headers.keySet()
|
||||
.stream()
|
||||
.filter(headerName -> !DISALLOWED_HEADERS_SET.contains(headerName))
|
||||
.collect(Collectors.toMap(
|
||||
Function.identity(),
|
||||
headers::get));
|
||||
|
||||
filteredHeaders.computeIfAbsent("Accept", key -> List.of("*/*"));
|
||||
|
||||
return filteredHeaders;
|
||||
}
|
||||
|
||||
private Map<String, Collection<String>> castMapCollectType(Map<String, List<String>> map) {
|
||||
final Map<String, Collection<String>> result = new HashMap<>();
|
||||
map.forEach((key, value) -> result.put(key, new HashSet<>(value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private String[] asString(Map<String, Collection<String>> headers) {
|
||||
return headers.entrySet().stream()
|
||||
.flatMap(entry -> entry.getValue()
|
||||
.stream()
|
||||
.map(value -> Arrays.asList(entry.getKey(), value))
|
||||
.flatMap(List::stream))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.geedge.asw.module.runner.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.runner.entity.JobEntity;
|
||||
import net.geedge.asw.module.runner.service.IJobService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/job")
|
||||
public class JobController {
|
||||
|
||||
@Autowired
|
||||
private IJobService jobService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
JobEntity jobEntity = jobService.queryInfo(id);
|
||||
return R.ok().putData("record", jobEntity);
|
||||
}
|
||||
|
||||
@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 = jobService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R add(@RequestBody JobEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getRunnerId()).notEmpty(RCode.RUNNER_ID_CANNOT_EMPTY)
|
||||
.and(entity.getPackageId()).notEmpty(RCode.PACKAGE_ID_CANNOT_EMPTY)
|
||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
JobEntity jobEntity = jobService.saveJob(entity);
|
||||
return R.ok().putData("id", jobEntity.getId());
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public R delete(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
jobService.removeJob(T.ListUtil.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/cancel")
|
||||
public R cancel(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
// TODO 其他处理
|
||||
|
||||
// update state
|
||||
jobService.update(new LambdaUpdateWrapper<JobEntity>()
|
||||
.in(JobEntity::getId, ids)
|
||||
.set(JobEntity::getStatus, "cancel")
|
||||
);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package net.geedge.asw.module.runner.controller;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.net.url.UrlBuilder;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import net.geedge.asw.common.config.SpringContextUtils;
|
||||
import net.geedge.asw.common.util.*;
|
||||
import net.geedge.asw.module.feign.client.WebSharkClient;
|
||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||
import net.geedge.asw.module.runner.service.IPcapService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/pcap")
|
||||
public class PcapController {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private IPcapService pcapService;
|
||||
|
||||
@Value("${webShark.url:127.0.0.1:8085}")
|
||||
private String websharkurl;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
PcapEntity pcapEntity = pcapService.queryInfo(id);
|
||||
return R.ok().putData("record", pcapEntity);
|
||||
}
|
||||
|
||||
@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 = pcapService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R add(@RequestParam(value = "files", required = true) List<MultipartFile> fileList,
|
||||
@RequestParam(value = "descriptions", required = false) List<String> descriptionList,
|
||||
@RequestParam(required = false) String workbookId,
|
||||
@RequestParam(required = false) String workspaceId) throws IOException {
|
||||
T.VerifyUtil.is(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
List<Object> recordList = T.ListUtil.list(true);
|
||||
for (int i = 0; i < fileList.size(); i++) {
|
||||
MultipartFile file = fileList.get(i);
|
||||
String description = T.StrUtil.emptyToDefault(T.CollUtil.get(descriptionList, i), "");
|
||||
PcapEntity pcapEntity = pcapService.savePcap(file.getResource(), description, workbookId, workspaceId);
|
||||
recordList.add(
|
||||
T.MapUtil.builder()
|
||||
.put("id", pcapEntity.getId())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
return R.ok().putData("records", recordList);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R update(@RequestBody List<Map<String, String>> body) {
|
||||
List<Object> recordList = T.ListUtil.list(true);
|
||||
for (Map<String, String> map : body) {
|
||||
String id = T.MapUtil.getStr(map, "id", "");
|
||||
if (T.StrUtil.isEmpty(id)) {
|
||||
continue;
|
||||
}
|
||||
String description = T.MapUtil.getStr(map, "description", "");
|
||||
pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
|
||||
.eq(PcapEntity::getId, id)
|
||||
.set(PcapEntity::getDescription, description)
|
||||
);
|
||||
recordList.add(
|
||||
T.MapUtil.builder()
|
||||
.put("id", id)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
return R.ok().putData("records", recordList);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public R delete(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
|
||||
pcapService.deletePcap(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/parse2session")
|
||||
public R parse2session(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
|
||||
pcapService.parse2session(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/download")
|
||||
public void download(HttpServletResponse response, String ids) throws IOException {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
List<String> pcapIdList = Arrays.asList(ids.split(","));
|
||||
List<PcapEntity> pcapList = pcapService.listByIds(pcapIdList);
|
||||
if (T.CollectionUtil.isNotEmpty(pcapList) && pcapList.size() == 1) {
|
||||
PcapEntity first = pcapList.getFirst();
|
||||
File pcapFile = T.FileUtil.file(first.getPath());
|
||||
ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, first.getName(), T.FileUtil.readBytes(pcapFile));
|
||||
}
|
||||
if (pcapList.size() > 1) {
|
||||
File zipFile = T.FileUtil.file(T.StrUtil.concat(true, Constants.TEMP_PATH, "/", "pcap-", DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN) + ".zip"));
|
||||
List<File> fileList = pcapList.stream().map(x -> T.FileUtil.file(x.getPath())).toList();
|
||||
T.ZipUtil.zip(zipFile, false, fileList.toArray(new File[0]));
|
||||
ResponseUtil.downloadFile(response, zipFile.getName(), T.FileUtil.readBytes(zipFile));
|
||||
T.FileUtil.del(zipFile);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/webshark")
|
||||
public R webshark(@PathVariable String id) {
|
||||
T.VerifyUtil.is(id).notEmpty();
|
||||
|
||||
HashMap<Object, Object> result = T.MapUtil.newHashMap();
|
||||
PcapEntity pcap = pcapService.getById(id);
|
||||
File pcapFile = T.FileUtil.file(pcap.getPath());
|
||||
String uploadFileName = T.StrUtil.concat(true, id, ".", T.FileUtil.getSuffix(pcapFile));
|
||||
File newFile = FileUtil.copy(pcapFile, FileUtil.file(Constants.TEMP_PATH, uploadFileName), false);
|
||||
try {
|
||||
WebSharkClient webSharkClient = (WebSharkClient) SpringContextUtils.getBean("webSharkClient");
|
||||
JSONObject obj = webSharkClient.upload(newFile);
|
||||
|
||||
String baseUrl = UrlBuilder.ofHttp(websharkurl)
|
||||
.addPath("/webshark")
|
||||
.toString();
|
||||
result.put("fileName", uploadFileName);
|
||||
result.put("url", baseUrl);
|
||||
}catch (Exception e){
|
||||
log.error(e, "webshark upload pcap error, id: {}", pcap.getId());
|
||||
throw new ASWException(RCode.PCAP_UPLOAD_WEB_SHARK_ERROR);
|
||||
}finally {
|
||||
FileUtil.del(newFile);
|
||||
}
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
|
||||
@PutMapping("/unparse2session")
|
||||
public R unparse2session(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
|
||||
pcapService.unparse2session(ids);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package net.geedge.asw.module.runner.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
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.T;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||
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.IRunnerService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/runner")
|
||||
public class RunnerController {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private IJobService jobService;
|
||||
|
||||
@Autowired
|
||||
private IRunnerService runnerService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
RunnerEntity runnerEntity = runnerService.getById(id);
|
||||
return R.ok().putData("record", runnerEntity);
|
||||
}
|
||||
|
||||
@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 = runnerService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R add(@RequestBody RunnerEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
RunnerEntity runner = runnerService.saveRunner(entity);
|
||||
return R.ok().putData("record", runner);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R update(@RequestBody RunnerEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
|
||||
RunnerEntity runner = runnerService.updateRunner(entity);
|
||||
return R.ok().putData("record", runner);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public R delete(@PathVariable("id") String id) {
|
||||
runnerService.removeById(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@PostMapping("/register")
|
||||
public void register(@RequestHeader("Authorization") String token, HttpServletResponse response) throws IOException {
|
||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||
if (!T.StrUtil.equals("online", status)) {
|
||||
log.warn("[register] [runner is offline] [token: {}]", token);
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||
}
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@PostMapping("/heartbeat")
|
||||
public void heartbeat(@RequestHeader("Authorization") String token, @RequestBody Map<String, Integer> platformMap,
|
||||
HttpServletResponse response) throws IOException {
|
||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||
if (!T.StrUtil.equals("online", status)) {
|
||||
log.warn("[heartbeat] [runner is offline] [token: {}]", token);
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||
return;
|
||||
}
|
||||
|
||||
// update last_heartbeat_timestamp
|
||||
runnerService.update(new LambdaUpdateWrapper<RunnerEntity>()
|
||||
.set(RunnerEntity::getLastHeartbeatTimestamp, System.currentTimeMillis())
|
||||
.eq(RunnerEntity::getId, runner.getId()));
|
||||
|
||||
// findjob by platform
|
||||
String platform = platformMap.entrySet().stream().filter(entry -> entry.getValue() > 0).findFirst().map(entry -> entry.getKey()).orElseGet(null);
|
||||
JobEntity job = jobService.assignPendingJob(runner.getId(), platform);
|
||||
if (T.ObjectUtil.isNotNull(job)) {
|
||||
// package
|
||||
PackageEntity pkg = job.getPkg();
|
||||
Map<String, String> pkgInfo = T.MapUtil.builder("id", pkg.getId())
|
||||
.put("platform", pkg.getPlatform())
|
||||
.put("identifier", pkg.getIdentifier())
|
||||
.put("version", pkg.getVersion())
|
||||
.build();
|
||||
|
||||
// playbook
|
||||
PlaybookEntity playbook = job.getPlaybook();
|
||||
Map<String, String> pbInfo = T.MapUtil.builder("id", playbook.getId())
|
||||
.put("name", playbook.getName())
|
||||
.build();
|
||||
|
||||
// response job info
|
||||
Map<Object, Object> responseData = T.MapUtil.builder()
|
||||
.put("id", job.getId())
|
||||
.put("pkg", pkgInfo)
|
||||
.put("playbook", pbInfo)
|
||||
.build();
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("text/html; charset=UTF-8");
|
||||
response.getWriter().write(T.JSONUtil.toJsonStr(responseData));
|
||||
}
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@PutMapping("/trace/{jobId}")
|
||||
public void trace(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestBody byte[] bytes,
|
||||
HttpServletResponse response) throws IOException {
|
||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||
if (!T.StrUtil.equals("online", status)) {
|
||||
log.warn("[trace] [runner is offline] [token: {}]", token);
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 追加到文件中
|
||||
String content = T.StrUtil.str(bytes, T.CharsetUtil.CHARSET_UTF_8);
|
||||
jobService.appendTraceLogStrToFile(jobId, content);
|
||||
} catch (Exception e) {
|
||||
log.error("[trace] [error] [job: {}]", jobId);
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@PutMapping("/jobResult/{jobId}")
|
||||
public void jobResult(@RequestHeader("Authorization") String token, @PathVariable String jobId, @RequestParam String state,
|
||||
@RequestParam(value = "file", required = false) MultipartFile pcapFile,
|
||||
HttpServletResponse response) throws IOException {
|
||||
RunnerEntity runner = runnerService.getOne(new LambdaUpdateWrapper<RunnerEntity>().eq(RunnerEntity::getToken, token));
|
||||
String status = Opt.ofNullable(runner).map(RunnerEntity::getStatus).orElseGet(() -> null);
|
||||
if (!T.StrUtil.equals("online", status)) {
|
||||
log.warn("[trace] [runner is offline] [token: {}]", token);
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Runner is offline");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新任务状态
|
||||
jobService.updateJobResult(jobId, state, pcapFile);
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/net/geedge/asw/module/runner/dao/JobDao.java
Normal file
19
src/main/java/net/geedge/asw/module/runner/dao/JobDao.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package net.geedge.asw.module.runner.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface JobDao extends BaseMapper<JobEntity>{
|
||||
|
||||
List<JobEntity> queryList(IPage page, Map<String, Object> params);
|
||||
|
||||
JobEntity getPendingJobByPlatform(@Param("platform") String platform);
|
||||
|
||||
}
|
||||
16
src/main/java/net/geedge/asw/module/runner/dao/PcapDao.java
Normal file
16
src/main/java/net/geedge/asw/module/runner/dao/PcapDao.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package net.geedge.asw.module.runner.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface PcapDao extends BaseMapper<PcapEntity>{
|
||||
|
||||
List<PcapEntity> queryList(Page page, Map<String, Object> params);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.geedge.asw.module.runner.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface PlaybookDao extends BaseMapper<PlaybookEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.geedge.asw.module.runner.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface RunnerDao extends BaseMapper<RunnerEntity>{
|
||||
|
||||
List<RunnerEntity> queryList(Page page, Map<String, Object> params);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.geedge.asw.module.runner.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.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
|
||||
@Data
|
||||
@TableName("job")
|
||||
public class JobEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String playbookId;
|
||||
private String packageId;
|
||||
private String runnerId;
|
||||
private String scheduleId;
|
||||
private String signatureIds;
|
||||
private String tags;
|
||||
private Long startTimestamp;
|
||||
private Long endTimestamp;
|
||||
private String status;
|
||||
private String pcapId;
|
||||
private String logPath;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String workbookId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private ApplicationEntity application;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonProperty(value = "package")
|
||||
private PackageEntity pkg;
|
||||
|
||||
@TableField(exist = false)
|
||||
private RunnerEntity runner;
|
||||
|
||||
@TableField(exist = false)
|
||||
private PlaybookEntity playbook;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.geedge.asw.module.runner.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.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import net.geedge.asw.module.app.entity.ApplicationEntity;
|
||||
import net.geedge.asw.module.app.entity.PackageEntity;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||
|
||||
@Data
|
||||
@TableName("pcap")
|
||||
public class PcapEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String path;
|
||||
private Long size;
|
||||
private String md5;
|
||||
private String status;
|
||||
private String summary;
|
||||
private Long createTimestamp;
|
||||
private String createUserId;
|
||||
private String workspaceId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private WorkspaceEntity workspace;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String jobId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private ApplicationEntity application;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonProperty(value = "package")
|
||||
private PackageEntity pkg;
|
||||
|
||||
@TableField(exist = false)
|
||||
private RunnerEntity runner;
|
||||
|
||||
@TableField(exist = false)
|
||||
private PlaybookEntity playbook;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.geedge.asw.module.runner.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("playbook")
|
||||
public class PlaybookEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String appId;
|
||||
private String tags;
|
||||
private String script;
|
||||
private Long opVersion;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.geedge.asw.module.runner.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("runner")
|
||||
public class RunnerEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String token;
|
||||
private String tags;
|
||||
private String supportPlatforms;
|
||||
private Integer shareFlag;
|
||||
private String description;
|
||||
private String status;
|
||||
private Long lastHeartbeatTimestamp;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
private String workspaceId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.geedge.asw.module.runner.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.runner.entity.JobEntity;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IJobService extends IService<JobEntity>{
|
||||
|
||||
JobEntity queryInfo(String id);
|
||||
|
||||
Page queryList(Map<String, Object> params);
|
||||
|
||||
JobEntity saveJob(JobEntity entity);
|
||||
|
||||
void removeJob(List<String> ids);
|
||||
|
||||
JobEntity assignPendingJob(String id, String platform);
|
||||
|
||||
void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException;
|
||||
|
||||
void updateJobResult(String jobId, String state, MultipartFile pcapFile);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.geedge.asw.module.runner.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface IPcapService extends IService<PcapEntity>{
|
||||
|
||||
PcapEntity queryInfo(String id);
|
||||
|
||||
Page queryList(Map<String, Object> params);
|
||||
|
||||
PcapEntity savePcap(String jobId, Resource fileResource);
|
||||
|
||||
PcapEntity savePcap(Resource fileResource,String... params);
|
||||
|
||||
void deletePcap(String... ids);
|
||||
|
||||
void parse2session(String... ids);
|
||||
|
||||
void unparse2session(String[] ids);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.geedge.asw.module.runner.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||
|
||||
public interface IPlaybookService extends IService<PlaybookEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.geedge.asw.module.runner.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface IRunnerService extends IService<RunnerEntity>{
|
||||
|
||||
Page queryList(Map<String, Object> params);
|
||||
|
||||
RunnerEntity saveRunner(RunnerEntity entity);
|
||||
|
||||
RunnerEntity updateRunner(RunnerEntity entity);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package net.geedge.asw.module.runner.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.common.util.RCode;
|
||||
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.service.IApplicationService;
|
||||
import net.geedge.asw.module.app.service.IPackageService;
|
||||
import net.geedge.asw.module.runner.dao.JobDao;
|
||||
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.RunnerEntity;
|
||||
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.IRunnerService;
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJobService {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private IPcapService pcapService;
|
||||
|
||||
@Autowired
|
||||
private IRunnerService runnerService;
|
||||
|
||||
@Autowired
|
||||
private IPlaybookService playbookService;
|
||||
|
||||
@Autowired
|
||||
private IPackageService packageService;
|
||||
|
||||
@Autowired
|
||||
private IApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private IWorkbookResourceService workbookResourceService;
|
||||
|
||||
/**
|
||||
* rootPath/result/{jobId}
|
||||
*
|
||||
* @param jobId
|
||||
* @return
|
||||
*/
|
||||
private String getJobResultPath(String jobId) {
|
||||
return T.FileUtil.file(T.WebPathUtil.getRootPath(), "result", jobId).getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobEntity queryInfo(String id) {
|
||||
JobEntity job = this.getById(id);
|
||||
T.VerifyUtil.is(job).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||
|
||||
RunnerEntity runner = runnerService.getById(job.getRunnerId());
|
||||
job.setRunner(runner);
|
||||
|
||||
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
||||
job.setPlaybook(playbook);
|
||||
|
||||
PackageEntity pkg = packageService.getById(job.getPackageId());
|
||||
job.setPkg(pkg);
|
||||
|
||||
if (T.ObjectUtil.isNotNull(playbook)) {
|
||||
ApplicationEntity application = applicationService.getById(playbook.getAppId());
|
||||
job.setApplication(application);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
List<JobEntity> jobList = this.getBaseMapper().queryList(page, params);
|
||||
page.setRecords(jobList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public JobEntity saveJob(JobEntity entity) {
|
||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
|
||||
// save
|
||||
this.save(entity);
|
||||
|
||||
// workbook resource
|
||||
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.JOB.getValue());
|
||||
|
||||
// trace log file path
|
||||
File traceLogFile = T.FileUtil.file(this.getJobResultPath(entity.getId()), "trace.log");
|
||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||
.set(JobEntity::getLogPath, traceLogFile.getPath())
|
||||
.eq(JobEntity::getId, entity.getId()));
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeJob(List<String> ids) {
|
||||
// remove
|
||||
this.removeBatchByIds(ids);
|
||||
// workbook resource
|
||||
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.JOB.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized JobEntity assignPendingJob(String runnerId, String platform) {
|
||||
if (T.StrUtil.hasEmpty(runnerId, platform)) {
|
||||
return null;
|
||||
}
|
||||
// query
|
||||
JobEntity job = this.getBaseMapper().getPendingJobByPlatform(platform);
|
||||
if (T.ObjectUtil.isNotNull(job)) {
|
||||
// update
|
||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||
.set(JobEntity::getRunnerId, runnerId)
|
||||
.set(JobEntity::getStatus, RunnerConstant.JobStatus.RUNNING.getValue())
|
||||
.set(JobEntity::getStartTimestamp, System.currentTimeMillis())
|
||||
.eq(JobEntity::getId, job.getId())
|
||||
);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTraceLogStrToFile(String jobId, String content) throws RuntimeException {
|
||||
try {
|
||||
JobEntity job = this.getById(jobId);
|
||||
if (T.StrUtil.isEmpty(job.getLogPath())) {
|
||||
File traceLogFile = T.FileUtil.file(this.getJobResultPath(jobId), "trace.log");
|
||||
job.setLogPath(traceLogFile.getPath());
|
||||
}
|
||||
// append content
|
||||
T.FileUtil.appendString(content, T.FileUtil.file(job.getLogPath()), T.CharsetUtil.CHARSET_UTF_8);
|
||||
} catch (IORuntimeException e) {
|
||||
log.error(e, "[appendTraceLogStrToFile] [error] [job: {}] [content: {}]", jobId, content);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateJobResult(String jobId, String state, MultipartFile pcapFile) {
|
||||
String pcapId = T.StrUtil.EMPTY;
|
||||
// save pcap file
|
||||
if (T.ObjectUtil.isNotNull(pcapFile)) {
|
||||
PcapEntity pcapEntity = pcapService.savePcap(jobId, pcapFile.getResource());
|
||||
pcapId = pcapEntity.getId();
|
||||
}
|
||||
|
||||
// update job status&pcap_id
|
||||
state = T.StrUtil.equals("success", state) ? RunnerConstant.JobStatus.PASSED.getValue() : state;
|
||||
this.update(new LambdaUpdateWrapper<JobEntity>()
|
||||
.set(JobEntity::getStatus, state)
|
||||
.set(T.StrUtil.isNotEmpty(pcapId), JobEntity::getPcapId, pcapId)
|
||||
.set(JobEntity::getEndTimestamp, System.currentTimeMillis())
|
||||
.eq(JobEntity::getId, jobId)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
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.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.common.config.SpringContextUtils;
|
||||
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.entity.ApplicationEntity;
|
||||
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.runner.dao.PcapDao;
|
||||
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.RunnerEntity;
|
||||
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.IRunnerService;
|
||||
import net.geedge.asw.module.runner.util.PcapParserThread;
|
||||
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 net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.opensearch.client.opensearch.OpenSearchClient;
|
||||
import org.opensearch.client.opensearch.indices.DeleteIndexRequest;
|
||||
import org.opensearch.client.opensearch.indices.ExistsRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements IPcapService {
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Value("${sharkdApi.host:127.0.0.1}")
|
||||
private String sharkdApiHostAddr;
|
||||
|
||||
@Autowired
|
||||
private IJobService jobService;
|
||||
|
||||
@Autowired
|
||||
private IRunnerService runnerService;
|
||||
|
||||
@Autowired
|
||||
private IPlaybookService playbookService;
|
||||
|
||||
@Autowired
|
||||
private IPackageService packageService;
|
||||
|
||||
@Autowired
|
||||
private IApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private IWorkbookResourceService workbookResourceService;
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceService workspaceService;
|
||||
|
||||
@Override
|
||||
public PcapEntity queryInfo(String id) {
|
||||
PcapEntity pcap = this.getById(id);
|
||||
T.VerifyUtil.is(pcap).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||
|
||||
JobEntity job = jobService.getOne(new LambdaQueryWrapper<JobEntity>().eq(JobEntity::getPcapId, pcap.getId()));
|
||||
if (T.ObjectUtil.isNotNull(job)) {
|
||||
pcap.setJobId(job.getId());
|
||||
|
||||
RunnerEntity runner = runnerService.getById(job.getRunnerId());
|
||||
pcap.setRunner(runner);
|
||||
|
||||
PackageEntity pkg = packageService.getById(job.getPackageId());
|
||||
pcap.setPkg(pkg);
|
||||
|
||||
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId());
|
||||
pcap.setPlaybook(playbook);
|
||||
|
||||
if (T.ObjectUtil.isNotNull(playbook)) {
|
||||
ApplicationEntity application = applicationService.getById(playbook.getAppId());
|
||||
pcap.setApplication(application);
|
||||
}
|
||||
}
|
||||
return pcap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
List<PcapEntity> pcapList = this.getBaseMapper().queryList(page, params);
|
||||
page.setRecords(pcapList);
|
||||
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
|
||||
public PcapEntity savePcap(Resource fileResource, String... params) {
|
||||
String description = T.ArrayUtil.get(params, 0);
|
||||
String workbookId = T.ArrayUtil.get(params, 1);
|
||||
String workspaceId = T.ArrayUtil.get(params, 2);
|
||||
String createUserId = T.StrUtil.emptyToDefault(T.ArrayUtil.get(params, 3), StpUtil.getLoginIdAsString());
|
||||
|
||||
PcapEntity entity = new PcapEntity();
|
||||
try {
|
||||
entity.setName(fileResource.getFilename());
|
||||
entity.setDescription(description);
|
||||
|
||||
byte[] bytes = fileResource.getInputStream().readAllBytes();
|
||||
entity.setSize((long) bytes.length);
|
||||
|
||||
entity.setStatus(RunnerConstant.PcapStatus.UPLOADED.getValue());
|
||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||
entity.setCreateUserId(createUserId);
|
||||
entity.setWorkspaceId(workspaceId);
|
||||
|
||||
// path
|
||||
File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), workspaceId, fileResource.getFilename());
|
||||
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
|
||||
entity.setPath(destination.getPath());
|
||||
|
||||
// md5
|
||||
String md5Hex = T.DigestUtil.md5Hex(destination);
|
||||
entity.setMd5(md5Hex);
|
||||
|
||||
// 根据文件 md5值 判断是否已上存在,存在则响应当前实体
|
||||
PcapEntity findPcapByMd5 = this.getOne(new LambdaQueryWrapper<PcapEntity>().eq(PcapEntity::getMd5, md5Hex).eq(PcapEntity::getWorkspaceId, workspaceId));
|
||||
if (T.ObjectUtil.isNotNull(findPcapByMd5)) {
|
||||
return findPcapByMd5;
|
||||
}
|
||||
|
||||
// save
|
||||
this.save(entity);
|
||||
|
||||
// workbook resource
|
||||
workbookResourceService.saveResource(workbookId, entity.getId(), WorkbookConstant.ResourceType.PCAP.getValue());
|
||||
} catch (IOException e) {
|
||||
log.error(e, "[savePcap] [error] [workspaceId: {}]", workspaceId);
|
||||
throw new ASWException(RCode.ERROR);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deletePcap(String... ids) {
|
||||
for (String id : ids) {
|
||||
PcapEntity pcap = this.getById(id);
|
||||
// remove file
|
||||
T.FileUtil.del(pcap.getPath());
|
||||
|
||||
// remove
|
||||
this.removeById(id);
|
||||
|
||||
// update job pcap_id
|
||||
jobService.update(new LambdaUpdateWrapper<JobEntity>()
|
||||
.set(JobEntity::getPcapId, "")
|
||||
.eq(JobEntity::getPcapId, id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse2session(String... ids) {
|
||||
List<Runnable> taskList = T.ListUtil.list(true);
|
||||
Long maxFileSize = 0L;
|
||||
|
||||
// parse thread config properties
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("sharkdApiHostAddr", this.sharkdApiHostAddr);
|
||||
|
||||
for (String id : ids) {
|
||||
PcapEntity pcapEntity = this.getById(id);
|
||||
if (T.ObjectUtil.isNotNull(pcapEntity)) {
|
||||
WorkspaceEntity workspace = workspaceService.getById(pcapEntity.getWorkspaceId());
|
||||
pcapEntity.setWorkspace(workspace);
|
||||
|
||||
PcapParserThread pcapParserThread = new PcapParserThread();
|
||||
pcapParserThread.setPcapEntity(pcapEntity);
|
||||
pcapParserThread.setProperties(properties);
|
||||
taskList.add(pcapParserThread);
|
||||
|
||||
Long size = pcapEntity.getSize();
|
||||
if (size > maxFileSize) {
|
||||
maxFileSize = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (T.CollUtil.isNotEmpty(taskList)) {
|
||||
List<CompletableFuture<Void>> futures = taskList.stream()
|
||||
.map(task -> CompletableFuture.runAsync(task))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
CompletableFuture<Void> allTasksFuture = CompletableFuture.allOf(
|
||||
futures.toArray(new CompletableFuture[0])
|
||||
);
|
||||
|
||||
try {
|
||||
allTasksFuture.get(this.calculateParseThreadTimeout(maxFileSize), TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
log.error(e, "[parse2session] [error]");
|
||||
throw new ASWException(RCode.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unparse2session(String[] ids) {
|
||||
OpenSearchClient openSearchClient = (OpenSearchClient) SpringContextUtils.getBean("openSearchClient");
|
||||
|
||||
for (String id : ids) {
|
||||
PcapEntity pcapEntity = this.getById(id);
|
||||
if (T.ObjectUtil.isNotNull(pcapEntity)) {
|
||||
WorkspaceEntity workspace = workspaceService.getById(pcapEntity.getWorkspaceId());
|
||||
pcapEntity.setWorkspace(workspace);
|
||||
String pcapPath = pcapEntity.getPath();
|
||||
String md5Hex = T.DigestUtil.md5Hex(T.FileUtil.file(pcapPath));
|
||||
|
||||
String workspaceName = pcapEntity.getWorkspace().getName();
|
||||
String indexName = String.format("workspace-%s-%s", workspaceName, md5Hex);
|
||||
|
||||
try {
|
||||
// check if index exists
|
||||
boolean indexExists = openSearchClient.indices()
|
||||
.exists(new ExistsRequest.Builder().index(indexName).build())
|
||||
.value();
|
||||
|
||||
// if index exists, delete
|
||||
if (indexExists) {
|
||||
openSearchClient.indices().delete(new DeleteIndexRequest.Builder().index(indexName).build());
|
||||
log.debug("delete openSearch index: {}", indexName);
|
||||
}
|
||||
}catch (Exception e){
|
||||
log.error("delete openSearch index error index: {}", indexName);
|
||||
throw new RuntimeException("delete openSearch index error ", e);
|
||||
}
|
||||
pcapEntity.setStatus(RunnerConstant.PcapStatus.UPLOADED.getValue());
|
||||
this.updateById(pcapEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate Parse Thread Timeout
|
||||
*
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
private long calculateParseThreadTimeout(Long size) {
|
||||
// 小于 1MB 的文件,超时时间为 1分钟
|
||||
if (size <= 1048576) {
|
||||
return 60;
|
||||
// 小于10MB的文件,超时时间为 3分钟
|
||||
} else if (size <= 1048576 * 10) {
|
||||
return 60 * 3;
|
||||
// 其他,超时时间为 10分钟
|
||||
} else {
|
||||
return 60 * 10;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.geedge.asw.module.runner.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.module.runner.dao.PlaybookDao;
|
||||
import net.geedge.asw.module.runner.entity.PlaybookEntity;
|
||||
import net.geedge.asw.module.runner.service.IPlaybookService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class PlaybookServiceImpl extends ServiceImpl<PlaybookDao, PlaybookEntity> implements IPlaybookService {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.geedge.asw.module.runner.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
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.runner.dao.RunnerDao;
|
||||
import net.geedge.asw.module.runner.entity.RunnerEntity;
|
||||
import net.geedge.asw.module.runner.service.IRunnerService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class RunnerServiceImpl extends ServiceImpl<RunnerDao, RunnerEntity> implements IRunnerService {
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
List<RunnerEntity> jobList = this.getBaseMapper().queryList(page, params);
|
||||
page.setRecords(jobList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunnerEntity saveRunner(RunnerEntity entity) {
|
||||
entity.setCreateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setCreateUserId(StpUtil.getLoginIdAsString());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
|
||||
// token
|
||||
entity.setToken(T.IdUtil.fastSimpleUUID());
|
||||
|
||||
// save
|
||||
this.save(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunnerEntity updateRunner(RunnerEntity entity) {
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
|
||||
// update
|
||||
this.updateById(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package net.geedge.asw.module.runner.util;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.Data;
|
||||
import net.geedge.asw.common.config.SpringContextUtils;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.feign.client.GeoipClient;
|
||||
import net.geedge.asw.module.feign.client.ZeekClient;
|
||||
import net.geedge.asw.module.runner.entity.PcapEntity;
|
||||
import net.geedge.asw.module.runner.service.IPcapService;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.opensearch.client.opensearch.OpenSearchClient;
|
||||
import org.opensearch.client.opensearch.core.BulkRequest;
|
||||
import org.opensearch.client.opensearch.core.BulkResponse;
|
||||
import org.opensearch.client.opensearch.core.bulk.BulkResponseItem;
|
||||
import org.opensearch.client.opensearch.indices.CreateIndexRequest;
|
||||
import org.opensearch.client.opensearch.indices.DeleteIndexRequest;
|
||||
import org.opensearch.client.opensearch.indices.ExistsRequest;
|
||||
import org.opensearch.client.opensearch.indices.IndexSettings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.geedge.asw.module.runner.util.RunnerConstant.PcapStatus;
|
||||
|
||||
@Data
|
||||
public class PcapParserThread implements Runnable {
|
||||
|
||||
private Log log = Log.get();
|
||||
|
||||
private Properties properties;
|
||||
|
||||
private PcapEntity pcapEntity;
|
||||
private IPcapService pcapService;
|
||||
|
||||
private ZeekClient zeekClient;
|
||||
private GeoipClient geoipClient;
|
||||
private OpenSearchClient openSearchClient;
|
||||
|
||||
private void init() {
|
||||
pcapService = SpringContextUtils.getBean(IPcapService.class);
|
||||
zeekClient = (ZeekClient) SpringContextUtils.getBean("zeekClient");
|
||||
geoipClient = (GeoipClient) SpringContextUtils.getBean("geoipClient");
|
||||
openSearchClient = (OpenSearchClient) SpringContextUtils.getBean("openSearchClient");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.currentThread().setName("pcap-parser-thread-" + pcapEntity.getId());
|
||||
log.info("job pcap parser start");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("pcapInfo: {}", T.JSONUtil.toJsonStr(pcapEntity));
|
||||
}
|
||||
StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
try {
|
||||
// init
|
||||
this.init();
|
||||
// parsing
|
||||
this.updateStatus(PcapStatus.PARSING.getValue());
|
||||
// parser
|
||||
this.parser();
|
||||
// indexed
|
||||
this.updateStatus(PcapStatus.INDEXED.getValue());
|
||||
} catch (Exception e) {
|
||||
// error
|
||||
this.updateStatus(PcapStatus.ERROR.getValue());
|
||||
log.error(e, "job pcap parser error, id: {}", pcapEntity.getId());
|
||||
} finally {
|
||||
sw.stop();
|
||||
log.info("job pcap parser end. id: {} Run Time: {}", pcapEntity.getId(), sw.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parser
|
||||
*/
|
||||
private void parser() {
|
||||
// zeek
|
||||
JSONArray jsonArray = zeekClient.parser(T.FileUtil.file(pcapEntity.getPath()));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("[parse] [zeek parse pcap file] [size: {}]", jsonArray.size());
|
||||
}
|
||||
|
||||
// geoip
|
||||
List<String> ipList = jsonArray.stream()
|
||||
.map(obj -> T.MapUtil.getStr((JSONObject) obj, "id.resp_h", ""))
|
||||
.filter(s -> T.StrUtil.isNotEmpty(s))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<String, JSONObject> geoipInfo = this.queryGeoip(ipList);
|
||||
|
||||
// add custom field
|
||||
String pcapId = pcapEntity.getId();
|
||||
String pcapName = T.FileUtil.getName(pcapEntity.getPath());
|
||||
Long tcpStream = 0L, udpStream = 0L;
|
||||
|
||||
String sharkdApiHostAddr = properties.getProperty("sharkdApiHostAddr", "127.0.0.1");
|
||||
for (Object obj : jsonArray) {
|
||||
JSONObject pojo = (JSONObject) obj;
|
||||
pojo.put("pcap.id", pcapId);
|
||||
pojo.put("pcap.name", pcapName);
|
||||
|
||||
String proto = T.MapUtil.getStr(pojo, "proto", "");
|
||||
if (T.StrUtil.equalsIgnoreCase("tcp", proto)) {
|
||||
Long streamId = tcpStream++;
|
||||
pojo.put("pcap.tcp_stream", streamId);
|
||||
pojo.put("pcap.stream_url", String.format("http://%s/pcap/%s/tcp/%s", sharkdApiHostAddr, pcapId, streamId));
|
||||
}
|
||||
if (T.StrUtil.equalsIgnoreCase("udp", proto)) {
|
||||
Long streamId = udpStream++;
|
||||
pojo.put("pcap.udp_stream", streamId);
|
||||
pojo.put("pcap.stream_url", String.format("http://%s/pcap/%s/udp/%s", sharkdApiHostAddr, pcapId, streamId));
|
||||
}
|
||||
|
||||
String resp = T.MapUtil.getStr(pojo, "id.resp_h", "");
|
||||
if (T.StrUtil.isNotEmpty(resp)) {
|
||||
JSONObject jsonObject = T.MapUtil.get(geoipInfo, resp, JSONObject.class, new JSONObject());
|
||||
pojo.put("id.resp_country", T.MapUtil.getStr(jsonObject, "country", ""));
|
||||
pojo.put("id.resp_asn", T.MapUtil.getStr(jsonObject, "asn", ""));
|
||||
pojo.put("id.resp_asname", T.MapUtil.getStr(jsonObject, "asname", ""));
|
||||
}
|
||||
}
|
||||
|
||||
// summary
|
||||
this.statisticSummary(jsonArray);
|
||||
|
||||
// opensearch
|
||||
this.uploadToOpenSearch(jsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* query geoip
|
||||
*
|
||||
* @param ipList
|
||||
* @return
|
||||
*/
|
||||
private Map<String, JSONObject> queryGeoip(List<String> ipList) {
|
||||
JSONArray result = new JSONArray();
|
||||
int batchSize = 100;
|
||||
for (int i = 0; i < ipList.size(); i += batchSize) {
|
||||
List<String> currentBatch = ipList.subList(i, Math.min(i + batchSize, ipList.size()));
|
||||
String queryParam = currentBatch.stream().collect(Collectors.joining(","));
|
||||
JSONArray array = geoipClient.geoip(queryParam);
|
||||
result.addAll(array);
|
||||
}
|
||||
Map<String, JSONObject> map = result.stream().collect(
|
||||
Collectors.toMap(
|
||||
obj -> T.MapUtil.getStr((JSONObject) obj, "ip"),
|
||||
obj -> (JSONObject) obj
|
||||
));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* statistic summary
|
||||
*
|
||||
* @param jsonArray
|
||||
*/
|
||||
private void statisticSummary(JSONArray jsonArray) {
|
||||
if (T.ObjectUtil.isEmpty(jsonArray)) {
|
||||
log.warn("[statisticSummary] [data array is empty] [id: {}]", pcapEntity.getId());
|
||||
} else {
|
||||
Set<String> services = new HashSet<>();
|
||||
Long packets = 0L;
|
||||
for (Object obj : jsonArray) {
|
||||
JSONObject pojo = (JSONObject) obj;
|
||||
long origPkts = pojo.getLongValue("orig_pkts", 0);
|
||||
long respPkts = pojo.getLongValue("resp_pkts", 0);
|
||||
packets = packets + (origPkts + respPkts);
|
||||
|
||||
services.add(pojo.getString("proto"));
|
||||
services.add(pojo.getString("service"));
|
||||
}
|
||||
|
||||
JSONObject first = (JSONObject) jsonArray.getFirst();
|
||||
JSONObject last = (JSONObject) jsonArray.getLast();
|
||||
|
||||
Map<Object, Object> m = T.MapUtil.builder()
|
||||
.put("startTimestamp", first.getBigDecimal("ts"))
|
||||
.put("endTimestamp", last.getBigDecimal("ts"))
|
||||
.put("sessions", jsonArray.size())
|
||||
.put("packets", packets)
|
||||
.put("services", services)
|
||||
.build();
|
||||
pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
|
||||
.set(PcapEntity::getSummary, T.JSONUtil.toJsonStr(m))
|
||||
.eq(PcapEntity::getId, pcapEntity.getId())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload to opensearch
|
||||
*
|
||||
* @param jsonArray
|
||||
*/
|
||||
private void uploadToOpenSearch(JSONArray jsonArray) {
|
||||
String pcapPath = pcapEntity.getPath();
|
||||
String md5Hex = T.DigestUtil.md5Hex(T.FileUtil.file(pcapPath));
|
||||
|
||||
String workspaceName = pcapEntity.getWorkspace().getName();
|
||||
String indexName = String.format("workspace-%s-%s", workspaceName, md5Hex);
|
||||
|
||||
try {
|
||||
// check if index exists
|
||||
boolean indexExists = openSearchClient.indices()
|
||||
.exists(new ExistsRequest.Builder().index(indexName).build())
|
||||
.value();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("[uploadToOpenSearch] [index: {}] [exists: {}]", indexName, indexExists);
|
||||
}
|
||||
// if index exists, delete
|
||||
if (indexExists) {
|
||||
openSearchClient.indices().delete(new DeleteIndexRequest.Builder().index(indexName).build());
|
||||
log.debug("[uploadToOpenSearch] [index: {}] [deleted]", indexName);
|
||||
}
|
||||
|
||||
// create index with default settings
|
||||
openSearchClient.indices().create(
|
||||
new CreateIndexRequest.Builder()
|
||||
.index(indexName)
|
||||
.settings(new IndexSettings.Builder().build())
|
||||
.build()
|
||||
);
|
||||
|
||||
// upload data in bulk
|
||||
BulkRequest.Builder br = new BulkRequest.Builder();
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JSONObject jsonObject = (JSONObject) jsonArray.get(i);
|
||||
String id = String.valueOf(i);
|
||||
br.operations(op -> op.index(
|
||||
idx -> idx.index(indexName)
|
||||
.id(id)
|
||||
.document(jsonObject)
|
||||
));
|
||||
}
|
||||
BulkResponse result = openSearchClient.bulk(br.build());
|
||||
// log errors, if any
|
||||
if (result.errors()) {
|
||||
log.error("[uploadToOpenSearch] [bulk had errors]");
|
||||
for (BulkResponseItem item : result.items()) {
|
||||
if (item.error() != null) {
|
||||
log.error("[uploadToOpenSearch] [error reason]", item.error().reason());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("[uploadToOpenSearch] [error] [index: {}]", indexName);
|
||||
throw new RuntimeException("Failed to upload data to OpenSearch", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update pcap status
|
||||
*
|
||||
* @param status
|
||||
*/
|
||||
private void updateStatus(String status) {
|
||||
pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
|
||||
.set(PcapEntity::getStatus, status)
|
||||
.eq(PcapEntity::getId, pcapEntity.getId())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.geedge.asw.module.runner.util;
|
||||
|
||||
public class RunnerConstant {
|
||||
|
||||
|
||||
/**
|
||||
* job status
|
||||
*/
|
||||
public enum JobStatus {
|
||||
CREATED("created"),
|
||||
|
||||
PENDING("pending"),
|
||||
|
||||
RUNNING("running"),
|
||||
|
||||
PASSED("passed"),
|
||||
|
||||
FAILED("failed"),
|
||||
|
||||
CANCEL("cancel");
|
||||
|
||||
private String value;
|
||||
|
||||
JobStatus(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pcap status
|
||||
*/
|
||||
public enum PcapStatus {
|
||||
UPLOADED("Uploaded"),
|
||||
|
||||
PARSING("Parsing"),
|
||||
|
||||
INDEXED("Indexed"),
|
||||
|
||||
ERROR("Error");
|
||||
|
||||
private String value;
|
||||
|
||||
PcapStatus(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package net.geedge.asw.module.runner.util;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONConfig;
|
||||
import cn.hutool.log.Log;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.geedge.asw.common.config.SpringContextUtils;
|
||||
import net.geedge.asw.common.util.ASWException;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Deprecated
|
||||
@NoArgsConstructor
|
||||
public class SignatureExtract {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
private String id;
|
||||
private String path;
|
||||
|
||||
private String tsharkPath = "/usr/bin/tshark";
|
||||
|
||||
public SignatureExtract(String id, String path) {
|
||||
this.id = id;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* signature
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String signature() {
|
||||
log.info("[signature] [begin] [id: {}] [path: {}]", id, path);
|
||||
StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
try {
|
||||
this.tsharkPath = SpringContextUtils.getProperty("tshark.path", "/usr/bin/tshark");
|
||||
log.info("[signature] [tshark path: {}]", this.tsharkPath);
|
||||
|
||||
SignatureUtil signatureObject = new SignatureUtil(this.tsharkPath);
|
||||
signatureObject.getStreamSignatureFromTshrak(path);
|
||||
|
||||
List<Map<String, String>> allFrameSignatureDictList = signatureObject.getOutputDictList();
|
||||
|
||||
// Get basic information of TCP data streams
|
||||
List<Map<String, Object>> tcpStreamBasicInfoList = SignatureUtil.getTCPStreamBaseInfo(allFrameSignatureDictList);
|
||||
List<Map<String, Object>> tcpStreamAllInfoList = T.ListUtil.list(false, tcpStreamBasicInfoList);
|
||||
|
||||
// Get other information of TCP data streams
|
||||
// Processing data stream by stream
|
||||
for (int i = 0; i < tcpStreamAllInfoList.size(); i++) {
|
||||
String streamID = T.MapUtil.getStr(tcpStreamAllInfoList.get(i), "StreamID");
|
||||
// Get all the Frame IDs of the data stream
|
||||
List<Map<String, String>> tcpFrameSignatureList = signatureObject.getOneTcpFrameSignatureList(streamID);
|
||||
|
||||
// Merge signature information from all Frame IDs
|
||||
// TCP data flow analysis
|
||||
this.tcpDataFlowAnalysis(signatureObject, tcpStreamAllInfoList.get(i), tcpFrameSignatureList);
|
||||
// General data flow analysis (common, ip, dns, http, ssl)
|
||||
this.generalDataFlowAnalysis(signatureObject, tcpStreamAllInfoList.get(i), tcpFrameSignatureList);
|
||||
}
|
||||
|
||||
// Get basic information of UDP data streams
|
||||
List<Map<String, Object>> udpStreamBaseInfo = SignatureUtil.getUDPStreamBaseInfo(allFrameSignatureDictList);
|
||||
List<Map<String, Object>> udpStreamAllInfoList = T.ListUtil.list(false, udpStreamBaseInfo);
|
||||
// Get other information of UDP data streams
|
||||
// Processing data stream by stream
|
||||
for (int i = 0; i < udpStreamAllInfoList.size(); i++) {
|
||||
String streamID = T.MapUtil.getStr(udpStreamAllInfoList.get(i), "StreamID");
|
||||
// Get all the Frame IDs of the data stream
|
||||
List<Map<String, String>> udpFrameSignatureList = signatureObject.getOneUdpFrameSignatureList(streamID);
|
||||
// Merge signature information from all Frame IDs
|
||||
// UDP data flow analysis
|
||||
this.udpDataFlowAnalysis(signatureObject, udpStreamAllInfoList.get(i), udpFrameSignatureList);
|
||||
// General data flow analysis (common, ip, dns, http, ssl)
|
||||
this.generalDataFlowAnalysis(signatureObject, udpStreamAllInfoList.get(i), udpFrameSignatureList);
|
||||
}
|
||||
|
||||
// result
|
||||
List<Object> resultOutputDict = T.ListUtil.list(true);
|
||||
resultOutputDict.addAll(tcpStreamAllInfoList);
|
||||
resultOutputDict.addAll(udpStreamAllInfoList);
|
||||
|
||||
JSONConfig jsonConfig = new JSONConfig();
|
||||
jsonConfig.setKeyComparator(Comparator.comparing(String::toString));
|
||||
JSONArray jsonArray = new JSONArray(resultOutputDict, jsonConfig);
|
||||
return jsonArray.toJSONString(0);
|
||||
} catch (Exception e) {
|
||||
log.error(e, "[signature] [error] [id: {}] [path: {}]", id, path);
|
||||
throw new ASWException("pcap file parse error. pcap id: " + id);
|
||||
} finally {
|
||||
sw.stop();
|
||||
log.info("[signature] [finshed] [id: {}] [Run Time: {}]", id, sw.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* data field
|
||||
*
|
||||
* @param signatureObject
|
||||
* @param streamDict
|
||||
* @param frameSignatureList
|
||||
*/
|
||||
private void generalDataFlowAnalysis(SignatureUtil signatureObject, Map<String, Object> streamDict, List<Map<String, String>> frameSignatureList) {
|
||||
// common
|
||||
streamDict.put("common.server_fqdn", signatureObject.ssl_extensions_server_name(frameSignatureList));
|
||||
streamDict.put("common.app_id", new String[]{"unknow"});
|
||||
if (T.MapUtil.getStr(frameSignatureList.get(0), "ip.proto").equals("6")) {
|
||||
streamDict.put("srcport", signatureObject.tcp_srcport(frameSignatureList));
|
||||
streamDict.put("dstport", signatureObject.tcp_dstport(frameSignatureList));
|
||||
} else {
|
||||
streamDict.put("srcport", signatureObject.udp_srcport(frameSignatureList));
|
||||
streamDict.put("dstport", signatureObject.udp_dstport(frameSignatureList));
|
||||
}
|
||||
// ip
|
||||
streamDict.put("ip.src", signatureObject.ip_src(frameSignatureList));
|
||||
streamDict.put("ip.dst", signatureObject.ip_dst(frameSignatureList));
|
||||
streamDict.put("ip.proto", signatureObject.ip_proto(frameSignatureList));
|
||||
streamDict.put("heartbeat_flag", signatureObject.heartbeat_flag(frameSignatureList));
|
||||
// dns
|
||||
streamDict.put("dns.qry.name", signatureObject.dns_qry_name(frameSignatureList));
|
||||
// http
|
||||
streamDict.put("http.request.full_uri", signatureObject.http_request_full_uri(frameSignatureList));
|
||||
streamDict.put("http.request.header", signatureObject.http_request_header(frameSignatureList));
|
||||
streamDict.put("http.response.header", signatureObject.http_response_header(frameSignatureList));
|
||||
// ssl
|
||||
streamDict.put("ssl.handshake.certificate.algorithm_identifier", signatureObject.ssl_algorithm_identifier(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.serial_number", signatureObject.ssl_serial_number(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.issuer_common_name", signatureObject.ssl_issuer_common_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.issuer_organization_name", signatureObject.ssl_issuer_organization_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.issuer_country_name", signatureObject.ssl_issuer_country_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.subject_common_name", signatureObject.ssl_subject_common_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.subject_organization_name", signatureObject.ssl_subject_organization_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.subject_country_name", signatureObject.ssl_subject_country_name(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.not_valid_before", signatureObject.ssl_not_valid_before(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.not_valid_after", signatureObject.ssl_not_valid_after(frameSignatureList));
|
||||
streamDict.put("ssl.handshake.certificate.algorithm_id", signatureObject.ssl_algorithm_id(frameSignatureList));
|
||||
streamDict.put("ssl.analysis.ja3", signatureObject.ssl_ja3(frameSignatureList));
|
||||
streamDict.put("ssl.analysis.sni_absent", signatureObject.ssl_sni_absent(frameSignatureList));
|
||||
streamDict.put("ssl.analysis.ech_enabled", signatureObject.ssl_ech_enabled(frameSignatureList));
|
||||
streamDict.put("ssl.analysis.esni_enabled", signatureObject.ssl_analysis_esni_enabled(frameSignatureList));
|
||||
}
|
||||
|
||||
/**
|
||||
* udp
|
||||
*
|
||||
* @param signatureObject
|
||||
* @param streamDict
|
||||
* @param frameSignatureList
|
||||
*/
|
||||
private void udpDataFlowAnalysis(SignatureUtil signatureObject, Map<String, Object> streamDict, List<Map<String, String>> frameSignatureList) {
|
||||
streamDict.put("udp.payload.c2s_first_data", signatureObject.udp_c2s_first_data(frameSignatureList));
|
||||
streamDict.put("udp.payload.s2c_first_data", signatureObject.udp_s2c_first_data(frameSignatureList));
|
||||
streamDict.put("udp.payload.c2s_first_data_len", signatureObject.udp_c2s_first_data_len(frameSignatureList));
|
||||
streamDict.put("udp.payload.s2c_first_data_len", signatureObject.udp_s2c_first_data_len(frameSignatureList));
|
||||
streamDict.put("udp.payload", signatureObject.udp_get_payload(frameSignatureList));
|
||||
}
|
||||
|
||||
/**
|
||||
* tcp
|
||||
*
|
||||
* @param signatureObject
|
||||
* @param streamDict
|
||||
* @param frameSignatureList
|
||||
*/
|
||||
private void tcpDataFlowAnalysis(SignatureUtil signatureObject, Map<String, Object> streamDict, List<Map<String, String>> frameSignatureList) {
|
||||
streamDict.put("tcp.payload.c2s_first_data", signatureObject.tcp_c2s_first_data(frameSignatureList));
|
||||
streamDict.put("tcp.payload.s2c_first_data", signatureObject.tcp_s2c_first_data(frameSignatureList));
|
||||
streamDict.put("tcp.payload.c2s_first_data_len", signatureObject.tcp_c2s_first_data_len(frameSignatureList));
|
||||
streamDict.put("tcp.payload.s2c_first_data_len", signatureObject.tcp_s2c_first_data_len(frameSignatureList));
|
||||
streamDict.put("tcp.payload", signatureObject.tcp_get_payload(frameSignatureList));
|
||||
}
|
||||
}
|
||||
1076
src/main/java/net/geedge/asw/module/runner/util/SignatureUtil.java
Normal file
1076
src/main/java/net/geedge/asw/module/runner/util/SignatureUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,33 @@
|
||||
package net.geedge.asw.module.sys.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTUtil;
|
||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||
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.sys.entity.SysUserEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysAuthService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sys")
|
||||
@RequestMapping("/api/v1")
|
||||
public class SysAuthController {
|
||||
|
||||
@Autowired
|
||||
private ISysAuthService authService;
|
||||
|
||||
@Autowired
|
||||
private SaTokenConfig saTokenConfig;
|
||||
|
||||
record AuthRecord(String userName, String pwd) {}
|
||||
|
||||
@PostMapping("/login")
|
||||
@@ -32,6 +36,30 @@ public class SysAuthController {
|
||||
.notEmpty(RCode.SYS_USER_PWD_ERROR);
|
||||
SysUserEntity userEntity = authService.login(record.userName(), record.pwd());
|
||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||
|
||||
String tokenValue = tokenInfo.getTokenValue();
|
||||
|
||||
JWT jwt = JWTUtil.parseToken(tokenValue);
|
||||
|
||||
// payload
|
||||
jwt.setPayload("sub", userEntity.getUserName());
|
||||
|
||||
Map<String, Object> permissions = authService.userPermissions();
|
||||
|
||||
String roles = ((List<String>) T.JSONUtil.getByPath(T.JSONUtil.parse(permissions), "records.role.name")).stream()
|
||||
.distinct()
|
||||
.collect(Collectors.joining(","));
|
||||
jwt.setPayload("roles", roles);
|
||||
|
||||
Long eff = Long.valueOf(jwt.getPayload("eff").toString());
|
||||
jwt.setPayload("exp", eff == -1L ? -1 : (eff / 1000));
|
||||
jwt.setPayload("iat", System.currentTimeMillis() / 1000);
|
||||
jwt.setPayload("nbf", System.currentTimeMillis() / 1000);
|
||||
|
||||
String sign = jwt.sign(JWTSignerUtil.hs256(saTokenConfig.getJwtSecretKey().getBytes()));
|
||||
tokenInfo.setTokenValue(sign);
|
||||
StpUtil.setTokenValue(sign);
|
||||
|
||||
userEntity.setPwd(null);
|
||||
return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package net.geedge.asw.module.sys.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.sys.entity.SysI18nEntity;
|
||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysI18nService;
|
||||
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/i18n")
|
||||
public class SysI18nController {
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ISysI18nService sysI18nService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
SysI18nEntity entity = sysI18nService.getById(id);
|
||||
if (T.ObjectUtil.isNotNull(entity)) {
|
||||
SysUserEntity user = userService.getById(entity.getUpdateUserId());
|
||||
user.setPwd(null);
|
||||
entity.setUpdateUser(user);
|
||||
}
|
||||
return R.ok().putData("record", entity);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public R list(String ids, String q, String lang, String code, String value,
|
||||
@RequestParam(defaultValue = "1") Integer current,
|
||||
@RequestParam(defaultValue = "20") Integer size,
|
||||
@RequestParam(defaultValue = "name") String orderBy) {
|
||||
QueryWrapper<SysI18nEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in(T.StrUtil.isNotEmpty(ids), "id", T.StrUtil.split(ids, ','));
|
||||
if (T.StrUtil.isNotBlank(q)) {
|
||||
queryWrapper.and(wrapper -> wrapper.like("lang", q)
|
||||
.or().like("code", q)
|
||||
.or().like("value", q)
|
||||
.or().like("remark", q)
|
||||
);
|
||||
}
|
||||
queryWrapper.eq(T.StrUtil.isNotEmpty(lang), "lang", lang);
|
||||
queryWrapper.like(T.StrUtil.isNotEmpty(code), "code", code);
|
||||
queryWrapper.like(T.StrUtil.isNotEmpty(value), "value", value);
|
||||
Page<SysI18nEntity> page = Page.of(current, size);
|
||||
page.addOrder(T.PageUtil.decodeOrderByStr(orderBy));
|
||||
page = sysI18nService.page(page, queryWrapper);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping
|
||||
public R add(@RequestBody SysI18nEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getCode()).notEmpty()
|
||||
.and(entity.getValue()).notEmpty()
|
||||
.and(entity.getLang()).notEmpty();
|
||||
SysI18nEntity one = sysI18nService.getOne(new LambdaQueryWrapper<SysI18nEntity>()
|
||||
.eq(SysI18nEntity::getCode, entity.getCode())
|
||||
.eq(SysI18nEntity::getLang, entity.getLang()));
|
||||
if (T.ObjectUtil.isNotNull(one)) {
|
||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
||||
}
|
||||
if (T.ObjectUtil.isEmpty(entity.getName())) {
|
||||
entity.setName(entity.getCode());
|
||||
}
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
sysI18nService.save(entity);
|
||||
return R.ok().putData("id", entity.getId());
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R update(@RequestBody SysI18nEntity entity) {
|
||||
T.VerifyUtil.is(entity).notNull()
|
||||
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
|
||||
.and(entity.getCode()).notEmpty()
|
||||
.and(entity.getValue()).notEmpty()
|
||||
.and(entity.getLang()).notEmpty();
|
||||
SysI18nEntity one = sysI18nService.getOne(new LambdaQueryWrapper<SysI18nEntity>()
|
||||
.eq(SysI18nEntity::getCode, entity.getCode())
|
||||
.eq(SysI18nEntity::getLang, entity.getLang())
|
||||
.ne(SysI18nEntity::getId, entity.getId()));
|
||||
if (T.ObjectUtil.isNotNull(one)) {
|
||||
throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build();
|
||||
}
|
||||
if (T.ObjectUtil.isEmpty(entity.getName())) {
|
||||
entity.setName(entity.getCode());
|
||||
}
|
||||
entity.setUpdateTimestamp(System.currentTimeMillis());
|
||||
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
|
||||
sysI18nService.updateById(entity);
|
||||
return R.ok().putData("id", entity.getId());
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public R delete(String[] ids) {
|
||||
T.VerifyUtil.is(ids).notEmpty();
|
||||
sysI18nService.removeBatchByIds(T.ListUtil.of(ids));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/lang")
|
||||
public R lang(@RequestParam(required = false, defaultValue = "en,zh") String l) {
|
||||
List<String> langList = T.StrUtil.split(l, ',');
|
||||
Map result = T.MapUtil.builder().build();
|
||||
for (String lang : langList) {
|
||||
List<SysI18nEntity> dataList = sysI18nService.list(new LambdaQueryWrapper<SysI18nEntity>().eq(SysI18nEntity::getLang, lang));
|
||||
Map<String, String> collect = dataList.stream().collect(Collectors.toMap(SysI18nEntity::getCode, SysI18nEntity::getValue));
|
||||
result.put(lang, collect);
|
||||
}
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
@PutMapping("/clearCache")
|
||||
public R clearCache() {
|
||||
sysI18nService.clearCache();
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +1,19 @@
|
||||
package net.geedge.asw.module.sys.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
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.sys.entity.SysRoleEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysRoleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sys/role")
|
||||
@RequestMapping("/api/v1/role")
|
||||
public class SysRoleController {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
@@ -37,8 +27,10 @@ public class SysRoleController {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public R list(String ids, String name, @RequestParam(defaultValue = "1") Integer current,
|
||||
@RequestParam(defaultValue = "20") Integer size, @RequestParam(defaultValue = "name") String orderBy) {
|
||||
public R list(String ids, String name,
|
||||
@RequestParam(defaultValue = "1") Integer current,
|
||||
@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);
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
package net.geedge.asw.module.sys.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
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.extension.plugins.pagination.Page;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import net.geedge.asw.common.util.ASWException;
|
||||
import net.geedge.asw.common.util.Constants;
|
||||
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.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.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 org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sys/user")
|
||||
@RequestMapping("/api/v1/user")
|
||||
public class SysUserController {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
@@ -36,24 +26,35 @@ public class SysUserController {
|
||||
private ISysUserService userService;
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
@Autowired
|
||||
private ISysUserRoleService uerRoleService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
SysUserEntity entity = userService.getById(id);
|
||||
entity.setPwd(null);
|
||||
List<SysRoleEntity> roleList = roleService.listByIds(T.ListUtil.of(entity.getRoleIds()));
|
||||
entity.setRoles(roleList);
|
||||
if (T.ObjectUtil.isNotNull(entity)) {
|
||||
entity.setPwd(null);
|
||||
List<SysUserRoleEntity> userRoleList = uerRoleService.list(new LambdaQueryWrapper<SysUserRoleEntity>().eq(SysUserRoleEntity::getUserId, entity.getId()));
|
||||
if (T.CollUtil.isNotEmpty(userRoleList)) {
|
||||
List<String> roleIds = userRoleList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList());
|
||||
List<SysRoleEntity> roleList = roleService.listByIds(roleIds);
|
||||
entity.setRoles(roleList);
|
||||
}
|
||||
}
|
||||
return R.ok().putData("record", entity);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public R list(String name, @RequestParam(defaultValue = "1") Integer current,
|
||||
@RequestParam(defaultValue = "20") Integer size, @RequestParam(defaultValue = "name") String orderBy) {
|
||||
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<SysUserEntity>();
|
||||
public R list(String ids, String q,
|
||||
@RequestParam(defaultValue = "1") Integer current,
|
||||
@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"));
|
||||
if (T.StrUtil.isNotBlank(name)) {
|
||||
queryWrapper.and(wrapper -> wrapper.like("name", name).or().like("user_name", name));
|
||||
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));
|
||||
|
||||
10
src/main/java/net/geedge/asw/module/sys/dao/SysI18nDao.java
Normal file
10
src/main/java/net/geedge/asw/module/sys/dao/SysI18nDao.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package net.geedge.asw.module.sys.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.sys.entity.SysI18nEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysI18nDao extends BaseMapper<SysI18nEntity> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.geedge.asw.module.sys.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 java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@TableName("sys_i18n")
|
||||
public class SysI18nEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* i18n code
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 语言
|
||||
*/
|
||||
private String lang;
|
||||
/**
|
||||
* 翻译值
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 操作人
|
||||
*/
|
||||
private String updateUserId;
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private Long updateTimestamp;
|
||||
|
||||
@TableField(exist = false)
|
||||
private SysUserEntity updateUser;
|
||||
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@TableName("sys_role")
|
||||
public class SysRoleEntity {
|
||||
@@ -20,4 +22,8 @@ public class SysRoleEntity {
|
||||
@TableField(exist = false)
|
||||
private String[] menuIds;
|
||||
private Long createTimestamp;
|
||||
@TableField(exist = false)
|
||||
private List<SysMenuEntity> menus;
|
||||
@TableField(exist = false)
|
||||
private List<String> buttons;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,21 @@ public class SysUserEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@TableField("user_name")
|
||||
private String userName;
|
||||
|
||||
private String pwd;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String[] roleIds;
|
||||
private String roleIds;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<SysRoleEntity> roles;
|
||||
|
||||
private String accessLevel;
|
||||
|
||||
private Long createTimestamp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.geedge.asw.module.sys.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.sys.entity.SysI18nEntity;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public interface ISysI18nService extends IService<SysI18nEntity> {
|
||||
|
||||
String queryValue(String code);
|
||||
|
||||
String queryValue(String code, Object... param);
|
||||
|
||||
String queryValue(String code, String lang);
|
||||
|
||||
String queryValue(String code, Locale locale, Object... param);
|
||||
|
||||
String queryValueByName(String name, Object... param);
|
||||
|
||||
void clearCache();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package net.geedge.asw.module.sys.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import net.geedge.asw.common.util.ASWException;
|
||||
import net.geedge.asw.common.util.Constants;
|
||||
import net.geedge.asw.common.util.RCode;
|
||||
@@ -21,61 +17,107 @@ import net.geedge.asw.module.sys.entity.SysMenuEntity;
|
||||
import net.geedge.asw.module.sys.entity.SysRoleEntity;
|
||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysAuthService;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookMemberEntity;
|
||||
import net.geedge.asw.module.workbook.service.IWorkbookMemberService;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
|
||||
import net.geedge.asw.module.workspace.service.IWorkspaceMemberService;
|
||||
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class SysAuthServiceImpl implements ISysAuthService {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private SysUserDao userDao;
|
||||
@Autowired
|
||||
private SysRoleDao roleDao;
|
||||
@Autowired
|
||||
private SysUserDao userDao;
|
||||
|
||||
@Override
|
||||
public SysUserEntity login(String userName, String pwd) {
|
||||
SysUserEntity userEntity = userDao
|
||||
.selectOne(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getUserName, userName));
|
||||
if (T.ObjectUtil.isNull(userEntity)
|
||||
|| !T.StrUtil.equals(userEntity.getPwd(), T.AesUtil.encrypt(pwd, Constants.AES_KEY))) {
|
||||
log.warn("user login error, username: {}", userName);
|
||||
throw ASWException.builder().rcode(RCode.SYS_USER_PWD_ERROR).build();
|
||||
}
|
||||
StpUtil.login(userEntity.getId());
|
||||
log.info("user login success, userName: {}", userName);
|
||||
return userEntity;
|
||||
}
|
||||
@Autowired
|
||||
private SysRoleDao roleDao;
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
StpUtil.logout();
|
||||
}
|
||||
@Autowired
|
||||
private IWorkspaceService workspaceService;
|
||||
|
||||
/**
|
||||
* 获取登录用户权限
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> userPermissions() {
|
||||
Map<String, Object> result = T.MapUtil.newHashMap();
|
||||
String userId = StpUtil.getLoginIdAsString();
|
||||
List<SysRoleEntity> roleList = roleDao.findRoleByUserId(userId);
|
||||
result.put("roles", roleList);
|
||||
// 组织 menu数据
|
||||
List<SysMenuEntity> menuList = roleDao.findMenuByUserId(userId);
|
||||
List<String> buttonList = menuList.stream().filter(menu -> T.StrUtil.equalsIgnoreCase(menu.getType(), "button"))
|
||||
.map(menu -> menu.getName()).collect(Collectors.toList());
|
||||
result.put("buttons", buttonList);
|
||||
//生成 menu tree结构
|
||||
Map<String, List<SysMenuEntity>> groupMap = menuList.stream()
|
||||
.filter(menu -> T.StrUtil.equalsIgnoreCase(menu.getType(), "menu"))
|
||||
.collect(Collectors.groupingBy(SysMenuEntity::getPid));
|
||||
menuList.forEach(menu -> {
|
||||
menu.setChildren(groupMap.get(menu.getId()));
|
||||
});
|
||||
List<SysMenuEntity> collect = menuList.stream().filter(menu -> T.StrUtil.isBlank(menu.getPid()))
|
||||
.collect(Collectors.toList());
|
||||
result.put("menus", collect);
|
||||
@Autowired
|
||||
private IWorkspaceMemberService workspaceMemberService;
|
||||
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public SysUserEntity login(String userName, String pwd) {
|
||||
SysUserEntity userEntity = userDao
|
||||
.selectOne(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getUserName, userName));
|
||||
if (T.ObjectUtil.isNull(userEntity)
|
||||
|| !T.StrUtil.equals(userEntity.getPwd(), T.AesUtil.encrypt(pwd, Constants.AES_KEY))) {
|
||||
log.warn("user login error, username: {}", userName);
|
||||
throw ASWException.builder().rcode(RCode.SYS_USER_PWD_ERROR).build();
|
||||
}
|
||||
StpUtil.login(userEntity.getId());
|
||||
log.info("user login success, userName: {}", userName);
|
||||
return userEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
StpUtil.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户权限
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> userPermissions() {
|
||||
String userId = StpUtil.getLoginIdAsString();
|
||||
SysUserEntity sysUserEntity = userDao.selectById(userId);
|
||||
String accessLevel = sysUserEntity.getAccessLevel();
|
||||
|
||||
List<WorkspaceEntity> workspaceEntityList = workspaceService.list();
|
||||
if (accessLevel.equalsIgnoreCase("regular")) {
|
||||
List<WorkspaceMemberEntity> workbookMemberEntityList = workspaceMemberService.list(new LambdaQueryWrapper<WorkspaceMemberEntity>().eq(WorkspaceMemberEntity::getUserId, userId));
|
||||
List<String> workspaceIdList = workbookMemberEntityList.stream().map(x -> x.getWorkspaceId()).toList();
|
||||
workspaceEntityList = workspaceService.list(new LambdaQueryWrapper<WorkspaceEntity>().in(WorkspaceEntity::getId, workspaceIdList));
|
||||
// public workspace
|
||||
List<WorkspaceEntity> publicWorkspaces = workspaceService.list(new LambdaQueryWrapper<WorkspaceEntity>().eq(WorkspaceEntity::getVisibility, "public"));
|
||||
workspaceEntityList.addAll(publicWorkspaces);
|
||||
}
|
||||
SysRoleEntity role = roleDao.findRoleByUserId(userId).get(0);
|
||||
// 组织 button 数据
|
||||
List<SysMenuEntity> menuList = roleDao.findMenuByUserId(userId);
|
||||
List<String> buttonList = menuList.stream().filter(menu -> T.StrUtil.equalsIgnoreCase(menu.getType(), "button"))
|
||||
.map(menu -> menu.getName()).collect(Collectors.toList());
|
||||
role.setButtons(buttonList);
|
||||
|
||||
//生成 menu tree结构
|
||||
Map<String, List<SysMenuEntity>> groupMap = menuList.stream()
|
||||
.filter(menu -> !T.StrUtil.equalsIgnoreCase(menu.getPid(), "0"))
|
||||
.collect(Collectors.groupingBy(SysMenuEntity::getPid));
|
||||
|
||||
menuList.forEach(menu -> {
|
||||
menu.setChildren(groupMap.get(menu.getId()));
|
||||
});
|
||||
|
||||
List<SysMenuEntity> collect = menuList.stream()
|
||||
.filter(menu -> T.StrUtil.equals(menu.getPid(), "0"))
|
||||
.filter(menu -> T.StrUtil.equals(menu.getType(), "menu"))
|
||||
.collect(Collectors.toList());
|
||||
role.setMenus(collect);
|
||||
|
||||
List records = ListUtil.list(false);
|
||||
for (WorkspaceEntity workspace : workspaceEntityList) {
|
||||
Map<Object, Object> map = MapUtil.builder()
|
||||
.put("workspace", workspace)
|
||||
.put("role", role)
|
||||
.build();
|
||||
records.add(map);
|
||||
}
|
||||
Map<String, Object> result = T.MapUtil.newHashMap();
|
||||
result.put("records", records);
|
||||
result.put("accessLevel", accessLevel);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.geedge.asw.module.sys.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.common.config.I18nConfig;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.sys.dao.SysI18nDao;
|
||||
import net.geedge.asw.module.sys.entity.SysI18nEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysI18nService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Service
|
||||
public class SysI18nServiceImpl extends ServiceImpl<SysI18nDao, SysI18nEntity> implements ISysI18nService {
|
||||
|
||||
@Autowired
|
||||
private I18nConfig i18nConfig;
|
||||
|
||||
@Override
|
||||
public String queryValue(String code) {
|
||||
return this.queryValue(code, this.getLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryValue(String code, Object... param) {
|
||||
return this.queryValue(code, this.getLocale(), param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryValue(String code, String lang) {
|
||||
return this.queryValue(code, Locale.of(lang));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryValue(String code, Locale locale, Object... param) {
|
||||
return i18nConfig.getSourceFromCache(code, locale, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryValueByName(String name, Object... param) {
|
||||
String language = this.getLocale().getLanguage();
|
||||
List<SysI18nEntity> list = this.list(new LambdaQueryWrapper<SysI18nEntity>().eq(SysI18nEntity::getName, name).eq(SysI18nEntity::getLang, language));
|
||||
if (T.CollUtil.isEmpty(list)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
SysI18nEntity sysI18nEntity = list.stream().findFirst().get();
|
||||
return this.queryValue(sysI18nEntity.getCode(), this.getLocale(), param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
i18nConfig.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* getLocale
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Locale getLocale() {
|
||||
return LocaleContextHolder.getLocale();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
package net.geedge.asw.module.sys.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.sys.dao.SysUserDao;
|
||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||
import net.geedge.asw.module.sys.entity.SysUserRoleEntity;
|
||||
import net.geedge.asw.module.sys.service.ISysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> implements ISysUserService {
|
||||
@@ -32,9 +29,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> i
|
||||
this.saveOrUpdate(entity);
|
||||
// 保存 user role关系
|
||||
List<SysUserRoleEntity> urList = T.ListUtil.list(false);
|
||||
Stream.of(entity.getRoleIds()).forEach(roleId -> {
|
||||
for (String roleId : T.StrUtil.split(entity.getRoleIds(), ",")) {
|
||||
urList.add(SysUserRoleEntity.builder().roleId(roleId).userId(entity.getId()).build());
|
||||
});
|
||||
}
|
||||
userRoleService.saveBatch(urList);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.geedge.asw.module.workbook.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface WorkbookDao extends BaseMapper<WorkbookEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.geedge.asw.module.workbook.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookMemberEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface WorkbookMemberDao extends BaseMapper<WorkbookMemberEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.geedge.asw.module.workbook.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookResourceEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface WorkbookResourceDao extends BaseMapper<WorkbookResourceEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.geedge.asw.module.workbook.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("workbook")
|
||||
public class WorkbookEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String tags;
|
||||
private String visibility;
|
||||
private String description;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.geedge.asw.module.workbook.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("workbook_member")
|
||||
public class WorkbookMemberEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String workbookId;
|
||||
private String userId;
|
||||
|
||||
private Long createTimestamp;
|
||||
private String createUserId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.geedge.asw.module.workbook.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("workbook_resource")
|
||||
public class WorkbookResourceEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String workbookId;
|
||||
private String resourceType;
|
||||
private String resourceId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.geedge.asw.module.workbook.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookMemberEntity;
|
||||
|
||||
public interface IWorkbookMemberService extends IService<WorkbookMemberEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.geedge.asw.module.workbook.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookResourceEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IWorkbookResourceService extends IService<WorkbookResourceEntity>{
|
||||
|
||||
void saveResource(String workbookId, String resourceId, String type);
|
||||
|
||||
void removeResource(List<String> resourceIdList, String type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.geedge.asw.module.workbook.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookEntity;
|
||||
|
||||
public interface IWorkbookService extends IService<WorkbookEntity>{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.geedge.asw.module.workbook.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.module.workbook.dao.WorkbookMemberDao;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookMemberEntity;
|
||||
import net.geedge.asw.module.workbook.service.IWorkbookMemberService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WorkbookMemberServiceImpl extends ServiceImpl<WorkbookMemberDao, WorkbookMemberEntity> implements IWorkbookMemberService {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.geedge.asw.module.workbook.service.impl;
|
||||
|
||||
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.T;
|
||||
import net.geedge.asw.module.workbook.dao.WorkbookResourceDao;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookResourceEntity;
|
||||
import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class WorkbookResourceServiceImpl extends ServiceImpl<WorkbookResourceDao, WorkbookResourceEntity> implements IWorkbookResourceService {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Override
|
||||
public void saveResource(String wbId, String resId, String type) {
|
||||
if (T.StrUtil.hasEmpty(wbId, resId, type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove
|
||||
this.remove(new LambdaQueryWrapper<WorkbookResourceEntity>()
|
||||
.eq(WorkbookResourceEntity::getResourceId, resId)
|
||||
.eq(WorkbookResourceEntity::getResourceType, type));
|
||||
|
||||
// insert
|
||||
WorkbookResourceEntity res = new WorkbookResourceEntity();
|
||||
res.setWorkbookId(wbId);
|
||||
res.setResourceId(resId);
|
||||
res.setResourceType(type);
|
||||
this.save(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeResource(List<String> resIdList, String type) {
|
||||
if (T.CollUtil.isEmpty(resIdList) || T.StrUtil.isEmpty(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove
|
||||
this.remove(new LambdaQueryWrapper<WorkbookResourceEntity>()
|
||||
.eq(WorkbookResourceEntity::getResourceType, type)
|
||||
.in(WorkbookResourceEntity::getResourceId, resIdList));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.geedge.asw.module.workbook.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import net.geedge.asw.module.workbook.dao.WorkbookDao;
|
||||
import net.geedge.asw.module.workbook.entity.WorkbookEntity;
|
||||
import net.geedge.asw.module.workbook.service.IWorkbookService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WorkbookServiceImpl extends ServiceImpl<WorkbookDao, WorkbookEntity> implements IWorkbookService {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.geedge.asw.module.workbook.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
public class WorkbookConstant {
|
||||
|
||||
|
||||
/**
|
||||
* resource type
|
||||
*/
|
||||
public enum ResourceType {
|
||||
PACKAGE("package"),
|
||||
SIGNATURE("signature"),
|
||||
JOB("job"),
|
||||
PCAP("pcap");
|
||||
|
||||
private String value;
|
||||
|
||||
ResourceType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ResourceType getInstanceByType(String type) {
|
||||
for (ResourceType v : values()) {
|
||||
if (StrUtil.equalsIgnoreCase(v.getValue(), type)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Failed to find resource type with parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package net.geedge.asw.module.workspace.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.common.util.VerifyUtil;
|
||||
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.entity.WorkspaceMemberEntity;
|
||||
import net.geedge.asw.module.workspace.service.IWorkspaceMemberService;
|
||||
import net.geedge.asw.module.workspace.service.IWorkspaceService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/workspace")
|
||||
public class WorkspaceController {
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceService workspaceService;
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceMemberService workspaceMemberService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R detail(@PathVariable("id") String id) {
|
||||
WorkspaceEntity workspace = workspaceService.getById(id);
|
||||
String createUserId = workspace.getCreateUserId();
|
||||
String updateUserId = workspace.getUpdateUserId();
|
||||
if (T.StrUtil.isNotEmpty(createUserId)) {
|
||||
SysUserEntity createUser = userService.getById(createUserId);
|
||||
workspace.setCreateUser(createUser);
|
||||
}
|
||||
if (T.StrUtil.isNotEmpty(updateUserId)) {
|
||||
SysUserEntity updateUser = userService.getById(updateUserId);
|
||||
workspace.setUpdateUser(updateUser);
|
||||
}
|
||||
return R.ok().putData("record", workspace);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public R list(@RequestParam Map<String, Object> params) {
|
||||
Page page = workspaceService.queryList(params);
|
||||
return R.ok(page);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R save(@RequestBody WorkspaceEntity workspace) {
|
||||
VerifyUtil.is(workspace).notNull()
|
||||
.and(workspace.getName()).notEmpty(RCode.WORKSPACE_NAME_CANNOT_EMPTY)
|
||||
.and(workspace.getVisibility()).notEmpty(RCode.WORKSPACE_VISIBILITY_CANNOT_EMPTY);
|
||||
|
||||
WorkspaceEntity workspaceEntity = workspaceService.saveWorkspace(workspace);
|
||||
return R.ok().putData("record", workspaceEntity.getId());
|
||||
}
|
||||
|
||||
|
||||
@PutMapping
|
||||
public R update(@RequestBody WorkspaceEntity workspace) {
|
||||
VerifyUtil.is(workspace).notNull()
|
||||
.and(workspace.getId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY)
|
||||
.and(workspace.getName()).notEmpty(RCode.WORKSPACE_NAME_CANNOT_EMPTY)
|
||||
.and(workspace.getVisibility()).notEmpty(RCode.WORKSPACE_VISIBILITY_CANNOT_EMPTY);
|
||||
|
||||
WorkspaceEntity workspaceEntity = workspaceService.updateWorkspace(workspace);
|
||||
return R.ok().putData("record", workspaceEntity.getId());
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public R delete(@RequestParam String ids) {
|
||||
VerifyUtil.is(ids).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
workspaceService.deleteWorkspace(ids);
|
||||
return R.ok();
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/{workspaceId}/member")
|
||||
public R getMember(@PathVariable String workspaceId) {
|
||||
List<WorkspaceMemberEntity> memberEntityList = workspaceMemberService.queryList(workspaceId);
|
||||
return R.ok().putData("record", memberEntityList);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/{workspaceId}/member")
|
||||
public R saveMember(@PathVariable String workspaceId, @RequestBody List<WorkspaceMemberEntity> workspaceMembers) {
|
||||
VerifyUtil.is(workspaceMembers).notEmpty(RCode.WORKSPACE_MEMBER_CANNOT_EMPTY)
|
||||
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
List<WorkspaceMemberEntity> workspaceMemberEntityList = workspaceMemberService.saveMember(workspaceId, workspaceMembers);
|
||||
return R.ok().putData("record", workspaceMemberEntityList);
|
||||
}
|
||||
|
||||
|
||||
@PutMapping("/{workspaceId}/member")
|
||||
public R updateMember(@PathVariable String workspaceId, @RequestBody List<WorkspaceMemberEntity> workspaceMembers) {
|
||||
VerifyUtil.is(workspaceMembers).notEmpty(RCode.WORKSPACE_MEMBER_CANNOT_EMPTY)
|
||||
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
|
||||
List<WorkspaceMemberEntity> workspaceMemberEntityList = workspaceMemberService.updateMember(workspaceId, workspaceMembers);
|
||||
return R.ok().putData("record", workspaceMemberEntityList);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{workspaceId}/member")
|
||||
public R deleteMember(@PathVariable String workspaceId, @RequestParam String userIds) {
|
||||
VerifyUtil.is(userIds).notEmpty(RCode.USER_ID_CANNOT_EMPTY);
|
||||
List<String> list = Arrays.asList(userIds.split(","));
|
||||
workspaceMemberService.remove(new LambdaQueryWrapper<WorkspaceMemberEntity>()
|
||||
.eq(WorkspaceMemberEntity::getWorkspaceId, workspaceId)
|
||||
.in(WorkspaceMemberEntity::getUserId, list));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.geedge.asw.module.workspace.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface WorkspaceDao extends BaseMapper<WorkspaceEntity> {
|
||||
|
||||
List<WorkspaceEntity> queryList(Page page, Map<String, Object> params);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.geedge.asw.module.workspace.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface WorkspaceMemberDao extends BaseMapper<WorkspaceMemberEntity> {
|
||||
|
||||
List<WorkspaceMemberEntity> queryList(String workspaceId);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.geedge.asw.module.workspace.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.SysRoleEntity;
|
||||
import net.geedge.asw.module.sys.entity.SysUserEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@TableName("workspace")
|
||||
public class WorkspaceEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
private String name;
|
||||
private String tags;
|
||||
private String visibility;
|
||||
private String description;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
private String createUserId;
|
||||
private String updateUserId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private SysUserEntity createUser;
|
||||
|
||||
@TableField(exist = false)
|
||||
private SysUserEntity updateUser;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<WorkspaceMemberEntity> members;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user