30 Commits

Author SHA1 Message Date
zhangshuai
62ea5f5542 fix: runner, pcap, job 接口添加 workspaceId path 参数 2024-08-09 14:48:23 +08:00
zhangshuai
357ee0be62 fix: package 接口url增加 workspaceId path 参数 2024-08-09 10:25:11 +08:00
zhangshuai
2945c51b0f fix: application 接口url增加 workspaceId path 参数 2024-08-09 10:01:00 +08:00
shizhendong
c3d9750bdc feat: ASW-30 新增 Application 分析重定向接口 2024-08-08 17:10:28 +08:00
zhangshuai
afb19a4326 fix: 调整 application path 2024-08-08 15:23:47 +08:00
zhangshuai
519b6e1c2d fix: 修改 index.html 路径 2024-08-08 14:52:22 +08:00
zhangshuai
e8b6e902c2 fix: 修改 index.html 路径 2024-08-08 14:13:41 +08:00
zhangshuai
a32327ad22 feat: ASW-31 asw controller 增加 GUIHistoryRouterFilter 2024-08-08 13:40:50 +08:00
zhangshuai
f7caf6262c feat: ASW-29 Application 恢复接口开发 2024-08-07 15:50:02 +08:00
zhangshuai
8932734ef6 fix: application log order by op_version desc 2024-08-07 11:11:29 +08:00
zhangshuai
3265d73dfe fix: application 页面添加 history 与 compare 按钮 2024-08-07 10:29:19 +08:00
zhangshuai
e88dc879e2 fix: application 不校验 description 2024-08-07 10:23:00 +08:00
zhangshuai
11a4000eb2 fix: 只允许applications,pcaps 菜单可见 2024-08-07 10:06:53 +08:00
zhangshuai
172bd9e890 fix: application 接口返回 user 对象 2024-08-06 18:15:39 +08:00
zhangshuai
d5f6aef383 fix: application 接口返回 user 对象 2024-08-06 18:15:11 +08:00
zhangshuai
875eb83d6e feat: ASW-26 pcap download 接口开发 2024-08-06 15:33:37 +08:00
zhangshuai
b6cbe6094f fix: application name 与 description 非空校验 2024-08-06 10:47:12 +08:00
zhangshuai
9a21b440b0 fix: update application.button order 2024-08-05 15:07:24 +08:00
zhangshuai
ba87a497bb feat: ASW-22 workspace 接口开发
1.workspace 接口开发
2.新增 application delete, edit, add 按钮
2024-08-05 15:01:35 +08:00
shizhendong
aaff071420 fix: 修复 pcap 重复上传时删除原始文件问题 2024-08-05 10:10:48 +08:00
shizhendong
a837a160f9 fix: 调整 pcap 文件解析 index_name= workspace-{workspace.name}-{pcap.md5} 2024-08-02 18:27:22 +08:00
shizhendong
af0d0e55ca feat: 集成 satoken jwt
1. 登录成功后返回 jwt token
2024-08-02 17:30:19 +08:00
zhangshuai
4b53e78124 fix: 删除 Signature 菜单,菜单补充 icon ,调整菜单 i18n 2024-08-02 14:52:56 +08:00
zhangshuai
2c8b299735 feat: application 详情接口增加 version 参数 2024-08-01 17:48:42 +08:00
zhangshuai
96483dc432 feat: ASW-21 用户权限查询接口接口开发 2024-08-01 17:09:29 +08:00
shizhendong
d9ec686bc7 feat: ASW-14 新增 pcap 解析接口 2024-07-30 21:10:39 +08:00
zhangshuai
17328600aa feat: ASW-18 application log 查询接口开发 2024-07-30 17:10:29 +08:00
zhangshuai
6b78f8e61a feat: ASW-18 application 接口开发 2024-07-30 16:02:32 +08:00
shizhendong
b5af3de27d fix: 补充提交 2024-07-30 14:00:25 +08:00
shizhendong
4a2d7f9adf feat: 调整 pcap 增删改查接口 2024-07-30 13:53:59 +08:00
64 changed files with 2522 additions and 252 deletions

36
pom.xml
View File

@@ -79,6 +79,14 @@
<artifactId>sa-token-spring-boot3-starter</artifactId> <artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>1.37.0</version>
</dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
@@ -143,6 +151,34 @@
<artifactId>simplemagic</artifactId> <artifactId>simplemagic</artifactId>
<version>1.16</version> <version>1.16</version>
</dependency> </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> </dependencies>
<build> <build>

View File

@@ -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);
}
}

View File

@@ -1,17 +1,23 @@
package net.geedge.asw.common.config; 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.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.config.SaTokenConfig; import java.util.concurrent.TimeUnit;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class SaTokenConfigure implements WebMvcConfigurer { public class SaTokenConfigure implements WebMvcConfigurer {
@@ -38,6 +44,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
config.setTokenStyle("simple-uuid"); // token 风格 config.setTokenStyle("simple-uuid"); // token 风格
config.setIsLog(false); // 是否输出操作日志 config.setIsLog(false); // 是否输出操作日志
config.setIsPrint(false); config.setIsPrint(false);
// jwt秘钥
config.setJwtSecretKey("ypCLARItfzxvdVqRwPcwIasdgAkhoubj");
// config.setIsReadCookie(false); // config.setIsReadCookie(false);
} }
@@ -50,4 +58,29 @@ public class SaTokenConfigure implements WebMvcConfigurer {
SaRouter.match("/api/v1/**").notMatch("/api/v1/login").check(r -> StpUtil.checkLogin()); SaRouter.match("/api/v1/**").notMatch("/api/v1/login").check(r -> StpUtil.checkLogin());
})).addPathPatterns("/**"); })).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);
}
});
}
} }

View File

@@ -20,4 +20,10 @@ public class Constants {
*/ */
public static final List<String> LANG_LIST = T.ListUtil.of("en", "zh"); public static final List<String> LANG_LIST = T.ListUtil.of("en", "zh");
/**
* 工作空间可见性列表
*/
public static final List<String> VISIBILITY_LIST = T.ListUtil.of("public", "private");
} }

View File

@@ -18,10 +18,21 @@ public enum RCode {
PARAM_CANNOT_EMPTY(100006, "parameter cannot be empty"), // parameter 不能为空 PARAM_CANNOT_EMPTY(100006, "parameter cannot be empty"), // parameter 不能为空
USER_NO_LOGIN(100007, "user not login"), // 用户未登录 USER_NO_LOGIN(100007, "user not login"), // 用户未登录
SYS_RECORD_NOT_FOUND(100008, "record not found"),// 未找到记录 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"),
// Application // Application
APP_ID_CANNOT_EMPTY(201001, "application id cannot be empty"), 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"),
// Package // Package
@@ -39,6 +50,15 @@ public enum RCode {
// Workspace // Workspace
WORKSPACE_ID_CANNOT_EMPTY(401001, "workspace id cannot be empty"), 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"),
SUCCESS(200, "success"); // 成功 SUCCESS(200, "success"); // 成功

View File

@@ -0,0 +1,146 @@
package net.geedge.asw.module.app.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse;
import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.R;
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.service.IApplicationService;
import net.geedge.asw.module.sys.entity.SysUserEntity;
import net.geedge.asw.module.sys.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/{workspaceId}/application")
public class ApplicationController {
@Autowired
private IApplicationService applicationService;
@Autowired
private ISysUserService userService;
@GetMapping("/{id}")
public R detail(@PathVariable String workspaceId,
@PathVariable String id) {
ApplicationEntity entity = applicationService.getOne(new LambdaQueryWrapper<ApplicationEntity>()
.eq(ApplicationEntity::getId, id)
.eq(ApplicationEntity::getWorkspaceId, workspaceId));
if (T.ObjectUtil.isNull(entity)) {
throw new ASWException(RCode.APP_NOT_EXIST);
}
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
entity.setCreateUser(createUser);
entity.setUpdateUser(updateUser);
return R.ok().putData("record", entity);
}
@GetMapping("/{id}/{version}")
public R detail(@PathVariable String workspaceId,
@PathVariable String id,
@PathVariable(required = false) String version) {
ApplicationEntity entity = applicationService.queryByApplicationAndLog(id, version, workspaceId);
if (T.ObjectUtil.isNull(entity)) {
throw new ASWException(RCode.APP_NOT_EXIST);
}
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
entity.setCreateUser(createUser);
entity.setUpdateUser(updateUser);
return R.ok().putData("record", entity);
}
@GetMapping
public R list(@PathVariable String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull()
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId", workspaceId);
Page page = applicationService.queryList(params);
return R.ok(page);
}
@PostMapping
public R add(@PathVariable String workspaceId,
@RequestBody ApplicationEntity entity) {
T.VerifyUtil.is(entity).notNull()
.and(entity.getName()).notEmpty(RCode.APP_NAME_CANNOT_EMPTY)
//.and(entity.getLongName()).notEmpty(RCode.APP_LONGNAME_CANNOT_EMPTY)
//.and(entity.getProperties()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
//.and(entity.getSurrogates()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
//.and(entity.getDescription()).notEmpty(RCode.APP_DESCRIPTION_CANNOT_EMPTY)
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
ApplicationEntity applicationEntity = applicationService.saveApplication(entity);
return R.ok().putData("id", applicationEntity.getId());
}
@PutMapping
public R update(@PathVariable String workspaceId,
@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.getLongName()).notEmpty(RCode.APP_LONGNAME_CANNOT_EMPTY)
//.and(entity.getProperties()).notEmpty(RCode.APP_PROPERTIES_CANNOT_EMPTY)
//.and(entity.getSurrogates()).notEmpty(RCode.APP_SURROGATES_CANNOT_EMPTY)
//.and(entity.getDescription()).notEmpty(RCode.APP_DESCRIPTION_CANNOT_EMPTY)
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
ApplicationEntity applicationEntity = applicationService.updateApplication(entity);
return R.ok().putData("id", applicationEntity.getId());
}
@DeleteMapping
public R delete(@PathVariable String workspaceId,
String[] ids) {
T.VerifyUtil.is(ids).notEmpty();
applicationService.removeApplication(T.ListUtil.of(ids), workspaceId);
return R.ok();
}
@GetMapping("/{id}/log")
public R queryLogList(@PathVariable String workspaceId,
@PathVariable("id") String id) {
List<ApplicationEntity> applicationEntityList = applicationService.queryLogList(id, workspaceId);
return R.ok().putData("record", applicationEntityList);
}
@GetMapping("/{id}/{oldVersion}/{newVersion}")
public R applicationCompare(@PathVariable String workspaceId,
@PathVariable("id") String id,
@PathVariable("oldVersion") String oldVersion,
@PathVariable("newVersion") String newVersion) {
List<ApplicationEntity> list = applicationService.compare(id, oldVersion, newVersion,workspaceId);
return R.ok().putData("record", list);
}
@PostMapping("/{id}/{version}/restore")
public R restore(@PathVariable String workspaceId,
@PathVariable("id") String id,
@PathVariable("version") String version) {
applicationService.restore(id, version, workspaceId);
return R.ok();
}
@GetMapping("/analyze")
public void analyze(@PathVariable String workspaceId,
@RequestParam String pcapIds,
HttpServletResponse response) throws IOException {
applicationService.redirectDiscoverPage(workspaceId, pcapIds, response);
}
}

View File

@@ -1,5 +1,6 @@
package net.geedge.asw.module.app.controller; package net.geedge.asw.module.app.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.geedge.asw.common.util.R; import net.geedge.asw.common.util.R;
import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.RCode;
@@ -12,53 +13,63 @@ import org.springframework.web.bind.annotation.*;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequestMapping("/api/v1/package") @RequestMapping("/api/v1/{workspaceId}/package")
public class PackageController { public class PackageController {
@Autowired @Autowired
private IPackageService packageService; private IPackageService packageService;
@GetMapping("/{id}") @GetMapping("/{id}")
public R detail(@PathVariable("id") String id) { public R detail(@PathVariable String workspaceId,
PackageEntity entity = packageService.getById(id); @PathVariable("id") String id) {
PackageEntity entity = packageService.getOne(new LambdaQueryWrapper<PackageEntity>()
.eq(PackageEntity::getId, id)
.eq(PackageEntity::getWorkspaceId, workspaceId));
return R.ok().putData("record", entity); return R.ok().putData("record", entity);
} }
@GetMapping @GetMapping
public R list(@RequestParam Map<String, Object> params) { public R list(@PathVariable String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull() T.VerifyUtil.is(params).notNull()
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId", workspaceId);
Page page = packageService.queryList(params); Page page = packageService.queryList(params);
return R.ok(page); return R.ok(page);
} }
@PostMapping @PostMapping
public R add(@RequestBody PackageEntity entity) { public R add(@PathVariable String workspaceId,
@RequestBody PackageEntity entity) {
T.VerifyUtil.is(entity).notNull() T.VerifyUtil.is(entity).notNull()
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY) .and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
.and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY) .and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY)
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
PackageEntity pkgEntity = packageService.savePackage(entity); PackageEntity pkgEntity = packageService.savePackage(entity);
return R.ok().putData("id", pkgEntity.getId()); return R.ok().putData("id", pkgEntity.getId());
} }
@PutMapping @PutMapping
public R update(@RequestBody PackageEntity entity) { public R update(@PathVariable String workspaceId,
@RequestBody PackageEntity entity) {
T.VerifyUtil.is(entity).notNull() T.VerifyUtil.is(entity).notNull()
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY) .and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
.and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY) .and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY)
.and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY) .and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY)
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
PackageEntity pkgEntity = packageService.updatePackage(entity); PackageEntity pkgEntity = packageService.updatePackage(entity);
return R.ok().putData("id", pkgEntity.getId()); return R.ok().putData("id", pkgEntity.getId());
} }
@DeleteMapping @DeleteMapping
public R delete(String[] ids) { public R delete(@PathVariable String workspaceId,
String[] ids) {
T.VerifyUtil.is(ids).notEmpty(); T.VerifyUtil.is(ids).notEmpty();
packageService.removePackage(T.ListUtil.of(ids)); packageService.removePackage(T.ListUtil.of(ids), workspaceId);
return R.ok(); return R.ok();
} }

View File

@@ -1,10 +1,26 @@
package net.geedge.asw.module.app.dao; package net.geedge.asw.module.app.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper @Mapper
public interface ApplicationDao extends BaseMapper<ApplicationEntity>{ 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} and app.workspace_id = #{workspaceId}")
ApplicationEntity queryByApplicationAndLog(String id, String version, String workspaceId);
List<ApplicationEntity> queryLogList(String id, String workspaceId);
List<ApplicationEntity> compare(@Param("params") Map<String, Object> params);
} }

View File

@@ -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> {
}

View File

@@ -1,9 +1,11 @@
package net.geedge.asw.module.app.entity; package net.geedge.asw.module.app.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import net.geedge.asw.module.sys.entity.SysUserEntity;
@Data @Data
@TableName("application") @TableName("application")
@@ -23,5 +25,12 @@ public class ApplicationEntity {
private String updateUserId; private String updateUserId;
private String workspaceId; private String workspaceId;
private Integer opVersion;
@TableField(exist = false)
private SysUserEntity createUser;
@TableField(exist = false)
private SysUserEntity updateUser;
} }

View File

@@ -0,0 +1,24 @@
package net.geedge.asw.module.app.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("application_log")
public class ApplicationLogEntity {
private String id;
private String name;
private String longName;
private String properties;
private String description;
private String surrogates;
private Long createTimestamp;
private Long updateTimestamp;
private String createUserId;
private String updateUserId;
private String workspaceId;
private Integer opVersion;
}

View File

@@ -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> {
}

View File

@@ -1,8 +1,32 @@
package net.geedge.asw.module.app.service; package net.geedge.asw.module.app.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public interface IApplicationService extends IService<ApplicationEntity>{ public interface IApplicationService extends IService<ApplicationEntity>{
Page queryList(Map<String, Object> params);
ApplicationEntity saveApplication(ApplicationEntity entity);
ApplicationEntity updateApplication(ApplicationEntity entity);
void removeApplication(List<String> ids, String workspaceId);
ApplicationEntity queryByApplicationAndLog(String id, String version, String workspaceId);
List<ApplicationEntity> compare(String id, String oldVersion, String newVersion, String workspaceId);
List<ApplicationEntity> queryLogList(String id, String workspaceId);
void restore(String id, String version, String workspaceId);
void redirectDiscoverPage(String workspaceId, String pcapIds, HttpServletResponse response) throws IOException;
} }

View File

@@ -15,5 +15,5 @@ public interface IPackageService extends IService<PackageEntity>{
PackageEntity updatePackage(PackageEntity entity); PackageEntity updatePackage(PackageEntity entity);
void removePackage(List<String> ids); void removePackage(List<String> ids, String workspaceId);
} }

View File

@@ -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 {
}

View File

@@ -1,13 +1,257 @@
package net.geedge.asw.module.app.service.impl; package net.geedge.asw.module.app.service.impl;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.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 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import net.geedge.asw.module.feign.client.KibanaClient;
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.dao.ApplicationDao;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
import net.geedge.asw.module.app.entity.ApplicationLogEntity;
import net.geedge.asw.module.app.service.IApplicationLogService;
import net.geedge.asw.module.app.service.IApplicationService; import net.geedge.asw.module.app.service.IApplicationService;
import net.geedge.asw.module.runner.entity.PcapEntity;
import net.geedge.asw.module.runner.service.IPcapService;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import net.geedge.asw.module.workspace.service.IWorkspaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service @Service
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService { public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements IApplicationService {
private static final Log log = Log.get();
@Value("${kibana.url:127.0.0.1:5601}")
private String kibanaUrl;
@Autowired
private IApplicationLogService applicationLogService;
@Autowired
private IWorkspaceService workspaceService;
@Autowired
private IPcapService pcapService;
@Resource
private KibanaClient kibanaClient;
@Override
public ApplicationEntity queryByApplicationAndLog(String id, String version, String workspaceId) {
ApplicationEntity entity = this.baseMapper.queryByApplicationAndLog(id, version, workspaceId);
return entity;
}
@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;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApplicationEntity saveApplication(ApplicationEntity entity) {
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
.eq(ApplicationEntity::getName, entity.getName()));
if (T.ObjectUtil.isNotNull(one)) {
throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build();
}
entity.setCreateTimestamp(System.currentTimeMillis());
entity.setUpdateTimestamp(System.currentTimeMillis());
entity.setCreateUserId(StpUtil.getLoginIdAsString());
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
// save
this.save(entity);
return entity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApplicationEntity updateApplication(ApplicationEntity entity) {
ApplicationEntity one = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
.eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId())
.eq(ApplicationEntity::getId, entity.getId()));
if (T.ObjectUtil.isNull(one)) {
throw ASWException.builder().rcode(RCode.APP_NOT_EXIST).build();
}
entity.setUpdateTimestamp(System.currentTimeMillis());
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
entity.setOpVersion(one.getOpVersion() + 1);
// update
this.updateById(entity);
// save log
this.saveApplcationToLog(one);
return entity;
}
private void saveApplcationToLog(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, String workspaceId) {
// remove
this.remove(new LambdaQueryWrapper<ApplicationEntity>()
.in(ApplicationEntity::getId, ids)
.eq(ApplicationEntity::getWorkspaceId, workspaceId));
applicationLogService.remove(new LambdaQueryWrapper<ApplicationLogEntity>()
.in(ApplicationLogEntity::getId, ids)
.eq(ApplicationLogEntity::getWorkspaceId, workspaceId));
}
@Override
public List<ApplicationEntity> queryLogList(String id, String workspaceId) {
List<ApplicationEntity> packageList = this.getBaseMapper().queryLogList(id, workspaceId);
return packageList;
}
@Override
public List<ApplicationEntity> compare(String id, String oldVersion, String newVersion, String workspaceId) {
Map<String, Object> params = Map.of("id", id, "versions", Arrays.asList(oldVersion, newVersion),"workspaceId",workspaceId);
List<ApplicationEntity> packageList = this.getBaseMapper().compare(params);
return packageList;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void restore(String id, String version, String workspaceId) {
// save current to log
ApplicationEntity curApplication = this.getOne(new LambdaQueryWrapper<ApplicationEntity>()
.eq(ApplicationEntity::getId, id)
.eq(ApplicationEntity::getWorkspaceId, workspaceId));
this.saveApplcationToLog(curApplication);
// restore
ApplicationLogEntity oldApplication = applicationLogService.getOne(new LambdaQueryWrapper<ApplicationLogEntity>()
.eq(ApplicationLogEntity::getId, id)
.eq(ApplicationLogEntity::getWorkspaceId, workspaceId)
.eq(ApplicationLogEntity::getOpVersion, version));
oldApplication.setUpdateTimestamp(System.currentTimeMillis());
oldApplication.setUpdateUserId(StpUtil.getLoginIdAsString());
oldApplication.setOpVersion(curApplication.getOpVersion() + 1);
ApplicationEntity application = T.BeanUtil.toBean(oldApplication, ApplicationEntity.class);
this.updateById(application);
}
/**
* 1. 根据 workspace_name 查询 index-pattern 是否存在
* 2. 不存在则创建索引
*
* 维护格式示例:
* {
* "type": "index-pattern",
* "id": "workspace_id",
* "attributes": {
* "title": "workspace-{workspace_name}-*"
* }
* }
* @param workspaceId
* @param pcapIds
* @param response
* @throws IOException
*/
@Override
public void redirectDiscoverPage(String workspaceId, String pcapIds, HttpServletResponse response) throws IOException {
// 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("[redirectDiscoverPage] [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 source = pcapList.stream()
.map(PcapEntity::getName)
.map(fileName -> "\"" + fileName + "\"")
.collect(Collectors.joining("|", "source: (", ")"));
String param3 = String.format("_q=(filters:!(),query:(language:lucene,query:'%s'))", source);
String query = String.format("?%s&%s&%s", param1, param2, param3);
String redirectUrl = baseUrl + "#" + query;
if(log.isDebugEnabled()){
log.debug("[redirectDiscoverPage] [url: {}]", redirectUrl);
}
// redirect
response.sendRedirect(redirectUrl);
}
} }

View File

@@ -80,9 +80,11 @@ public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> i
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void removePackage(List<String> ids) { public void removePackage(List<String> ids, String workspaceId) {
// remove // remove
this.removeBatchByIds(ids); this.remove(new LambdaQueryWrapper<PackageEntity>()
.eq(PackageEntity::getWorkspaceId, workspaceId)
.in(PackageEntity::getId, ids));
// workbook resource // workbook resource
workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue()); workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue());
} }

View File

@@ -0,0 +1,64 @@
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.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;
@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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View 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);
}

View 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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -13,33 +13,38 @@ import org.springframework.web.bind.annotation.*;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequestMapping("/api/v1/job") @RequestMapping("/api/v1/{workspaceId}/job")
public class JobController { public class JobController {
@Autowired @Autowired
private IJobService jobService; private IJobService jobService;
@GetMapping("/{id}") @GetMapping("/{id}")
public R detail(@PathVariable("id") String id) { public R detail(@PathVariable String workspaceId,
JobEntity jobEntity = jobService.queryInfo(id); @PathVariable("id") String id) {
JobEntity jobEntity = jobService.queryInfo(id, workspaceId);
return R.ok().putData("record", jobEntity); return R.ok().putData("record", jobEntity);
} }
@GetMapping @GetMapping
public R list(@RequestParam Map<String, Object> params) { public R list(@PathVariable String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull() T.VerifyUtil.is(params).notNull()
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId", workspaceId);
Page page = jobService.queryList(params); Page page = jobService.queryList(params);
return R.ok(page); return R.ok(page);
} }
@PostMapping @PostMapping
public R add(@RequestBody JobEntity entity) { public R add(@PathVariable String workspaceId,
@RequestBody JobEntity entity) {
T.VerifyUtil.is(entity).notNull() T.VerifyUtil.is(entity).notNull()
.and(entity.getRunnerId()).notEmpty(RCode.RUNNER_ID_CANNOT_EMPTY) .and(entity.getRunnerId()).notEmpty(RCode.RUNNER_ID_CANNOT_EMPTY)
.and(entity.getPackageId()).notEmpty(RCode.PACKAGE_ID_CANNOT_EMPTY) .and(entity.getPackageId()).notEmpty(RCode.PACKAGE_ID_CANNOT_EMPTY)
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
JobEntity jobEntity = jobService.saveJob(entity); JobEntity jobEntity = jobService.saveJob(entity);
return R.ok().putData("id", jobEntity.getId()); return R.ok().putData("id", jobEntity.getId());
} }

View File

@@ -1,21 +1,28 @@
package net.geedge.asw.module.runner.controller; package net.geedge.asw.module.runner.controller;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.log.Log; 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.plugins.pagination.Page;
import net.geedge.asw.common.util.R; import jakarta.servlet.http.HttpServletResponse;
import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.*;
import net.geedge.asw.common.util.T;
import net.geedge.asw.module.runner.entity.PcapEntity; import net.geedge.asw.module.runner.entity.PcapEntity;
import net.geedge.asw.module.runner.service.IPcapService; import net.geedge.asw.module.runner.service.IPcapService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequestMapping("/api/v1/pcap") @RequestMapping("/api/v1/{workspaceId}/pcap")
public class PcapController { public class PcapController {
private static final Log log = Log.get(); private static final Log log = Log.get();
@@ -24,35 +31,101 @@ public class PcapController {
private IPcapService pcapService; private IPcapService pcapService;
@GetMapping("/{id}") @GetMapping("/{id}")
public R detail(@PathVariable("id") String id) { public R detail(@PathVariable String workspaceId,
PcapEntity pcapEntity = pcapService.queryInfo(id); @PathVariable("id") String id) {
PcapEntity pcapEntity = pcapService.queryInfo(id,workspaceId);
return R.ok().putData("record", pcapEntity); return R.ok().putData("record", pcapEntity);
} }
@GetMapping @GetMapping
public R list(@RequestParam Map<String, Object> params) { public R list(@PathVariable String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull() T.VerifyUtil.is(params).notNull()
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId",workspaceId);
Page page = pcapService.queryList(params); Page page = pcapService.queryList(params);
return R.ok(page); return R.ok(page);
} }
@PostMapping @PostMapping
public R add(@RequestParam(value = "file", required = true) MultipartFile file, @Transactional(rollbackFor = Exception.class)
@RequestParam(required = false) String tags, 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 workbookId,
@RequestParam(required = false) String workspaceId) throws IOException { @RequestParam(required = false) String workspaceId) throws IOException {
T.VerifyUtil.is(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); T.VerifyUtil.is(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
PcapEntity pcapEntity = pcapService.savePcap(file.getResource(), tags, workbookId, workspaceId); List<Object> recordList = T.ListUtil.list(true);
return R.ok().putData("id", pcapEntity.getId()); 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);
} }
@DeleteMapping("/{id}") @PutMapping
public R delete(@PathVariable("id") String id) { @Transactional(rollbackFor = Exception.class)
pcapService.deletePcap(id); 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(); 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);
}
}
} }

View File

@@ -3,6 +3,7 @@ package net.geedge.asw.module.runner.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Opt;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@@ -23,7 +24,7 @@ import java.io.IOException;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequestMapping("/api/v1/runner") @RequestMapping("/api/v1/{workspaceId}/runner")
public class RunnerController { public class RunnerController {
private static final Log log = Log.get(); private static final Log log = Log.get();
@@ -35,35 +36,44 @@ public class RunnerController {
private IRunnerService runnerService; private IRunnerService runnerService;
@GetMapping("/{id}") @GetMapping("/{id}")
public R detail(@PathVariable("id") String id) { public R detail(@PathVariable String workspaceId,
RunnerEntity runnerEntity = runnerService.getById(id); @PathVariable("id") String id) {
RunnerEntity runnerEntity = runnerService.getOne(new LambdaQueryWrapper<RunnerEntity>()
.eq(RunnerEntity::getId, id)
.eq(RunnerEntity::getWorkspaceId, workspaceId));
return R.ok().putData("record", runnerEntity); return R.ok().putData("record", runnerEntity);
} }
@GetMapping @GetMapping
public R list(@RequestParam Map<String, Object> params) { public R list(@PathVariable String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull() T.VerifyUtil.is(params).notNull()
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId", workspaceId);
Page page = runnerService.queryList(params); Page page = runnerService.queryList(params);
return R.ok(page); return R.ok(page);
} }
@PostMapping @PostMapping
public R add(@RequestBody RunnerEntity entity) { public R add(@PathVariable String workspaceId,
@RequestBody RunnerEntity entity) {
T.VerifyUtil.is(entity).notNull() T.VerifyUtil.is(entity).notNull()
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
RunnerEntity runner = runnerService.saveRunner(entity); RunnerEntity runner = runnerService.saveRunner(entity);
return R.ok().putData("record", runner); return R.ok().putData("record", runner);
} }
@PutMapping @PutMapping
public R update(@RequestBody RunnerEntity entity) { public R update(@PathVariable String workspaceId,
@RequestBody RunnerEntity entity) {
T.VerifyUtil.is(entity).notNull() T.VerifyUtil.is(entity).notNull()
.and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY) .and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY)
.and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); .and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
entity.setWorkspaceId(workspaceId);
RunnerEntity runner = runnerService.updateRunner(entity); RunnerEntity runner = runnerService.updateRunner(entity);
return R.ok().putData("record", runner); return R.ok().putData("record", runner);
} }

View File

@@ -1,10 +0,0 @@
package net.geedge.asw.module.runner.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.geedge.asw.module.runner.entity.DecodeRecordEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DecodeRecordDao extends BaseMapper<DecodeRecordEntity>{
}

View File

@@ -1,19 +0,0 @@
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("decode_record")
public class DecodeRecordEntity {
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String pcapId;
private Long streamId;
private String streamAttributes;
private String workspaceId;
}

View File

@@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
import net.geedge.asw.module.app.entity.PackageEntity; import net.geedge.asw.module.app.entity.PackageEntity;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
@Data @Data
@TableName("pcap") @TableName("pcap")
@@ -16,21 +17,18 @@ public class PcapEntity {
@TableId(type = IdType.ASSIGN_UUID) @TableId(type = IdType.ASSIGN_UUID)
private String id; private String id;
private String name; private String name;
private String tags;
private String description; private String description;
private String path; private String path;
private Long size; private Long size;
private Long connections;
private Long hosts;
private String md5; private String md5;
private Long connectionTimeFirst;
private Long connectionTimeLast;
private String protocols;
private String status; private String status;
private Long createTimestamp; private Long createTimestamp;
private String createUserId; private String createUserId;
private String workspaceId; private String workspaceId;
@TableField(exist = false)
private WorkspaceEntity workspace;
@TableField(exist = false) @TableField(exist = false)
private String jobId; private String jobId;

View File

@@ -1,8 +0,0 @@
package net.geedge.asw.module.runner.service;
import com.baomidou.mybatisplus.extension.service.IService;
import net.geedge.asw.module.runner.entity.DecodeRecordEntity;
public interface IDecodeRecordService extends IService<DecodeRecordEntity>{
}

View File

@@ -10,7 +10,7 @@ import java.util.Map;
public interface IJobService extends IService<JobEntity>{ public interface IJobService extends IService<JobEntity>{
JobEntity queryInfo(String id); JobEntity queryInfo(String id, String workspaceId);
Page queryList(Map<String, Object> params); Page queryList(Map<String, Object> params);

View File

@@ -5,11 +5,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
import net.geedge.asw.module.runner.entity.PcapEntity; import net.geedge.asw.module.runner.entity.PcapEntity;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import java.util.List;
import java.util.Map; import java.util.Map;
public interface IPcapService extends IService<PcapEntity>{ public interface IPcapService extends IService<PcapEntity>{
PcapEntity queryInfo(String id); PcapEntity queryInfo(String id, String workspaceId);
Page queryList(Map<String, Object> params); Page queryList(Map<String, Object> params);
@@ -17,6 +18,8 @@ public interface IPcapService extends IService<PcapEntity>{
PcapEntity savePcap(Resource fileResource,String... params); PcapEntity savePcap(Resource fileResource,String... params);
void deletePcap(String id); void deletePcap(String... ids);
void parse2session(String... ids);
} }

View File

@@ -1,13 +0,0 @@
package net.geedge.asw.module.runner.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.module.runner.dao.DecodeRecordDao;
import net.geedge.asw.module.runner.entity.DecodeRecordEntity;
import net.geedge.asw.module.runner.service.IDecodeRecordService;
import org.springframework.stereotype.Service;
@Service
public class DecodeRecordServiceImpl extends ServiceImpl<DecodeRecordDao, DecodeRecordEntity> implements IDecodeRecordService {
}

View File

@@ -3,6 +3,7 @@ package net.geedge.asw.module.runner.service.impl;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IORuntimeException;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -67,21 +68,31 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
} }
@Override @Override
public JobEntity queryInfo(String id) { public JobEntity queryInfo(String id, String workspaceId) {
JobEntity job = this.getById(id); JobEntity job = this.getOne(new LambdaQueryWrapper<JobEntity>()
.eq(JobEntity::getId, id)
.eq(JobEntity::getWorkspaceId, workspaceId));
T.VerifyUtil.is(job).notNull(RCode.SYS_RECORD_NOT_FOUND); T.VerifyUtil.is(job).notNull(RCode.SYS_RECORD_NOT_FOUND);
RunnerEntity runner = runnerService.getById(job.getRunnerId()); RunnerEntity runner = runnerService.getOne(new LambdaQueryWrapper<RunnerEntity>()
.eq(RunnerEntity::getId, job.getRunnerId())
.eq(RunnerEntity::getWorkspaceId, workspaceId));
job.setRunner(runner); job.setRunner(runner);
PlaybookEntity playbook = playbookService.getById(job.getPlaybookId()); PlaybookEntity playbook = playbookService.getOne(new LambdaQueryWrapper<PlaybookEntity>()
.eq(PlaybookEntity::getId, job.getPlaybookId())
.eq(PlaybookEntity::getWorkspaceId, workspaceId));
job.setPlaybook(playbook); job.setPlaybook(playbook);
PackageEntity pkg = packageService.getById(job.getPackageId()); PackageEntity pkg = packageService.getOne(new LambdaQueryWrapper<PackageEntity>()
.eq(PackageEntity::getId, job.getPackageId())
.eq(PackageEntity::getWorkspaceId, workspaceId));
job.setPkg(pkg); job.setPkg(pkg);
if (T.ObjectUtil.isNotNull(playbook)) { if (T.ObjectUtil.isNotNull(playbook)) {
ApplicationEntity application = applicationService.getById(playbook.getAppId()); ApplicationEntity application = applicationService.getOne(new LambdaQueryWrapper<ApplicationEntity>()
.eq(ApplicationEntity::getId, playbook.getAppId())
.eq(ApplicationEntity::getWorkspaceId, workspaceId));
job.setApplication(application); job.setApplication(application);
} }
return job; return job;
@@ -106,9 +117,10 @@ public class JobServiceImpl extends ServiceImpl<JobDao, JobEntity> implements IJ
// save // save
this.save(entity); this.save(entity);
// workbook resource if (T.StrUtil.isEmpty(entity.getWorkbookId())){
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.JOB.getValue()); // workbook resource
workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.JOB.getValue());
}
// trace log file path // trace log file path
File traceLogFile = T.FileUtil.file(this.getJobResultPath(entity.getId()), "trace.log"); File traceLogFile = T.FileUtil.file(this.getJobResultPath(entity.getId()), "trace.log");
this.update(new LambdaUpdateWrapper<JobEntity>() this.update(new LambdaUpdateWrapper<JobEntity>()

View File

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.RCode;
import net.geedge.asw.common.util.T; import net.geedge.asw.common.util.T;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
@@ -25,6 +26,8 @@ import net.geedge.asw.module.runner.util.PcapParserThread;
import net.geedge.asw.module.runner.util.RunnerConstant; import net.geedge.asw.module.runner.util.RunnerConstant;
import net.geedge.asw.module.workbook.service.IWorkbookResourceService; import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
import net.geedge.asw.module.workbook.util.WorkbookConstant; 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.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@@ -35,6 +38,11 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
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 @Service
public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements IPcapService { public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements IPcapService {
@@ -58,9 +66,12 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
@Autowired @Autowired
private IWorkbookResourceService workbookResourceService; private IWorkbookResourceService workbookResourceService;
@Autowired
private IWorkspaceService workspaceService;
@Override @Override
public PcapEntity queryInfo(String id) { public PcapEntity queryInfo(String id, String workspaceId) {
PcapEntity pcap = this.getById(id); PcapEntity pcap = this.getOne(new LambdaQueryWrapper<PcapEntity>().eq(PcapEntity::getId, id).eq(PcapEntity::getWorkspaceId, workspaceId));
T.VerifyUtil.is(pcap).notNull(RCode.SYS_RECORD_NOT_FOUND); T.VerifyUtil.is(pcap).notNull(RCode.SYS_RECORD_NOT_FOUND);
JobEntity job = jobService.getOne(new LambdaQueryWrapper<JobEntity>().eq(JobEntity::getPcapId, pcap.getId())); JobEntity job = jobService.getOne(new LambdaQueryWrapper<JobEntity>().eq(JobEntity::getPcapId, pcap.getId()));
@@ -101,7 +112,7 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
@Override @Override
public PcapEntity savePcap(Resource fileResource, String... params) { public PcapEntity savePcap(Resource fileResource, String... params) {
String tags = T.ArrayUtil.get(params, 0); String description = T.ArrayUtil.get(params, 0);
String workbookId = T.ArrayUtil.get(params, 1); String workbookId = T.ArrayUtil.get(params, 1);
String workspaceId = T.ArrayUtil.get(params, 2); String workspaceId = T.ArrayUtil.get(params, 2);
String createUserId = T.StrUtil.emptyToDefault(T.ArrayUtil.get(params, 3), StpUtil.getLoginIdAsString()); String createUserId = T.StrUtil.emptyToDefault(T.ArrayUtil.get(params, 3), StpUtil.getLoginIdAsString());
@@ -109,7 +120,7 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
PcapEntity entity = new PcapEntity(); PcapEntity entity = new PcapEntity();
try { try {
entity.setName(fileResource.getFilename()); entity.setName(fileResource.getFilename());
entity.setTags(T.StrUtil.emptyToDefault(tags, "")); entity.setDescription(description);
byte[] bytes = fileResource.getInputStream().readAllBytes(); byte[] bytes = fileResource.getInputStream().readAllBytes();
entity.setSize((long) bytes.length); entity.setSize((long) bytes.length);
@@ -129,10 +140,8 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
entity.setMd5(md5Hex); entity.setMd5(md5Hex);
// 根据文件 md5值 判断是否已上存在,存在则响应当前实体 // 根据文件 md5值 判断是否已上存在,存在则响应当前实体
PcapEntity findPcapByMd5 = this.getOne(new LambdaQueryWrapper<PcapEntity>().eq(PcapEntity::getMd5, md5Hex)); PcapEntity findPcapByMd5 = this.getOne(new LambdaQueryWrapper<PcapEntity>().eq(PcapEntity::getMd5, md5Hex).eq(PcapEntity::getWorkspaceId, workspaceId));
if (T.ObjectUtil.isNotNull(findPcapByMd5)) { if (T.ObjectUtil.isNotNull(findPcapByMd5)) {
// 删除本次记录的文件
T.FileUtil.del(destination);
return findPcapByMd5; return findPcapByMd5;
} }
@@ -141,32 +150,87 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
// workbook resource // workbook resource
workbookResourceService.saveResource(workbookId, entity.getId(), WorkbookConstant.ResourceType.PCAP.getValue()); workbookResourceService.saveResource(workbookId, entity.getId(), WorkbookConstant.ResourceType.PCAP.getValue());
// parser
PcapParserThread pcapParserThread = new PcapParserThread();
pcapParserThread.setPcapEntity(entity);
T.ThreadUtil.execAsync(pcapParserThread);
} catch (IOException e) { } catch (IOException e) {
log.error(e, "[savePcap] [error] [workspaceId: {}]", workspaceId); log.error(e, "[savePcap] [error] [workspaceId: {}]", workspaceId);
throw new ASWException(RCode.ERROR);
} }
return entity; return entity;
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deletePcap(String pcapId) { public void deletePcap(String... ids) {
PcapEntity pcap = this.getById(pcapId); for (String id : ids) {
// remove file PcapEntity pcap = this.getById(id);
T.FileUtil.del(pcap.getPath()); // remove file
T.FileUtil.del(pcap.getPath());
// remove // remove
this.removeById(pcapId); this.removeById(id);
// update job pcap_id // update job pcap_id
jobService.update(new LambdaUpdateWrapper<JobEntity>() jobService.update(new LambdaUpdateWrapper<JobEntity>()
.set(JobEntity::getPcapId, "") .set(JobEntity::getPcapId, "")
.eq(JobEntity::getPcapId, pcapId) .eq(JobEntity::getPcapId, id)
); );
}
}
@Override
public void parse2session(String... ids) {
List<Runnable> taskList = T.ListUtil.list(true);
Long maxFileSize = 0L;
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);
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);
}
}
}
/**
* 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;
}
} }
} }

View File

@@ -1,14 +1,33 @@
package net.geedge.asw.module.runner.util; package net.geedge.asw.module.runner.util;
import cn.hutool.log.Log; import cn.hutool.log.Log;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.Data; import lombok.Data;
import net.geedge.asw.common.config.SpringContextUtils; import net.geedge.asw.common.config.SpringContextUtils;
import net.geedge.asw.common.util.T; 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.entity.PcapEntity;
import net.geedge.asw.module.runner.service.IPcapService; 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.File; import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.geedge.asw.module.runner.util.RunnerConstant.PcapStatus;
@Data @Data
public class PcapParserThread implements Runnable { public class PcapParserThread implements Runnable {
@@ -18,10 +37,15 @@ public class PcapParserThread implements Runnable {
private PcapEntity pcapEntity; private PcapEntity pcapEntity;
private IPcapService pcapService; private IPcapService pcapService;
private ZeekClient zeekClient;
private GeoipClient geoipClient;
private OpenSearchClient openSearchClient;
private void init() { private void init() {
pcapService = SpringContextUtils.getBean(IPcapService.class); pcapService = SpringContextUtils.getBean(IPcapService.class);
// analyzing zeekClient = (ZeekClient) SpringContextUtils.getBean("zeekClient");
this.updatePcapStatus(RunnerConstant.PcapStatus.ANALYZING.getValue()); geoipClient = (GeoipClient) SpringContextUtils.getBean("geoipClient");
openSearchClient = (OpenSearchClient) SpringContextUtils.getBean("openSearchClient");
} }
@Override @Override
@@ -31,19 +55,24 @@ public class PcapParserThread implements Runnable {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("pcapInfo: {}", T.JSONUtil.toJsonStr(pcapEntity)); log.debug("pcapInfo: {}", T.JSONUtil.toJsonStr(pcapEntity));
} }
StopWatch sw = new StopWatch();
sw.start();
try { try {
log.info("job pcap parser run start");
// init // init
this.init(); this.init();
// parsing
this.updateStatus(PcapStatus.PARSING.getValue());
// parser // parser
this.parser(); this.parser();
log.info("job pcap parser run end"); // indexed
this.updateStatus(PcapStatus.INDEXED.getValue());
} catch (Exception e) { } catch (Exception e) {
log.error(e, "job pcap parser error, pcap: {}", pcapEntity.getId()); // error
this.updateStatus(PcapStatus.ERROR.getValue());
log.error(e, "job pcap parser error, id: {}", pcapEntity.getId());
} finally { } finally {
// completed sw.stop();
this.updatePcapStatus(RunnerConstant.PcapStatus.COMPLETED.getValue()); log.info("job pcap parser end. id: {} Run Time: {}", pcapEntity.getId(), sw.toString());
log.info("job pcap parser end");
} }
} }
@@ -51,27 +80,140 @@ public class PcapParserThread implements Runnable {
* parser * parser
*/ */
private void parser() { private void parser() {
String id = pcapEntity.getId(); // zeek
String path = pcapEntity.getPath(); JSONArray jsonArray = zeekClient.parser(T.FileUtil.file(pcapEntity.getPath()));
SignatureExtract signatureExtract = new SignatureExtract(id, path); if (log.isDebugEnabled()) {
// signature log.debug("[parse] [zeek parse pcap file] [size: {}]", jsonArray.size());
String signature = signatureExtract.signature(); }
// 保存结果,和 pcap 文件同目录文件名pcap_id_signature.json
String parentPath = T.FileUtil.getParent(path, 1);
File signatureFile = T.FileUtil.file(parentPath, id + "_signature.json");
T.FileUtil.del(signatureFile);
T.FileUtil.writeUtf8String(signature, signatureFile);
// TODO // geoip
List<String> ipList = jsonArray.stream()
.flatMap(obj -> Stream.of(
T.MapUtil.getStr((JSONObject) obj, "id.orig_h", ""),
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 source&geoip_info field
String fileName = T.FileUtil.getName(pcapEntity.getPath());
for (Object obj : jsonArray) {
JSONObject pojo = (JSONObject) obj;
pojo.put("source", fileName);
String orig = T.MapUtil.getStr(pojo, "id.orig_h", "");
if (T.StrUtil.isNotEmpty(orig)) {
JSONObject jsonObject = T.MapUtil.get(geoipInfo, orig, JSONObject.class, new JSONObject());
pojo.put("id.orig_country", T.MapUtil.getStr(jsonObject, "country", ""));
pojo.put("id.orig_asn", T.MapUtil.getStr(jsonObject, "asn", ""));
pojo.put("id.orig_asname", T.MapUtil.getStr(jsonObject, "asname", ""));
}
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", ""));
}
}
// 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;
}
/**
* 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 * update pcap status
* *
* @param status * @param status
*/ */
private void updatePcapStatus(String status) { private void updateStatus(String status) {
pcapService.update(new LambdaUpdateWrapper<PcapEntity>() pcapService.update(new LambdaUpdateWrapper<PcapEntity>()
.set(PcapEntity::getStatus, status) .set(PcapEntity::getStatus, status)
.eq(PcapEntity::getId, pcapEntity.getId()) .eq(PcapEntity::getId, pcapEntity.getId())

View File

@@ -36,9 +36,11 @@ public class RunnerConstant {
public enum PcapStatus { public enum PcapStatus {
UPLOADED("Uploaded"), UPLOADED("Uploaded"),
ANALYZING("Analyzing"), PARSING("Parsing"),
COMPLETED("Completed"); INDEXED("Indexed"),
ERROR("Error");
private String value; private String value;

View File

@@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@Data @Data
@Deprecated
@NoArgsConstructor @NoArgsConstructor
public class SignatureExtract { public class SignatureExtract {

View File

@@ -23,6 +23,7 @@ import java.util.stream.Collectors;
* tshark 解析 pcap 文件 * tshark 解析 pcap 文件
*/ */
@Data @Data
@Deprecated
public class SignatureUtil { public class SignatureUtil {
private static final Log log = Log.get(); private static final Log log = Log.get();

View File

@@ -1,7 +1,11 @@
package net.geedge.asw.module.sys.controller; package net.geedge.asw.module.sys.controller;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil; 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.R;
import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.RCode;
import net.geedge.asw.common.util.T; import net.geedge.asw.common.util.T;
@@ -10,7 +14,9 @@ import net.geedge.asw.module.sys.service.ISysAuthService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/v1") @RequestMapping("/api/v1")
@@ -19,6 +25,9 @@ public class SysAuthController {
@Autowired @Autowired
private ISysAuthService authService; private ISysAuthService authService;
@Autowired
private SaTokenConfig saTokenConfig;
record AuthRecord(String userName, String pwd) {} record AuthRecord(String userName, String pwd) {}
@PostMapping("/login") @PostMapping("/login")
@@ -27,6 +36,30 @@ public class SysAuthController {
.notEmpty(RCode.SYS_USER_PWD_ERROR); .notEmpty(RCode.SYS_USER_PWD_ERROR);
SysUserEntity userEntity = authService.login(record.userName(), record.pwd()); SysUserEntity userEntity = authService.login(record.userName(), record.pwd());
SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); 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); userEntity.setPwd(null);
return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity); return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity);
} }

View File

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import java.util.List;
@Data @Data
@TableName("sys_role") @TableName("sys_role")
public class SysRoleEntity { public class SysRoleEntity {
@@ -20,4 +22,8 @@ public class SysRoleEntity {
@TableField(exist = false) @TableField(exist = false)
private String[] menuIds; private String[] menuIds;
private Long createTimestamp; private Long createTimestamp;
@TableField(exist = false)
private List<SysMenuEntity> menus;
@TableField(exist = false)
private List<String> buttons;
} }

View File

@@ -15,13 +15,21 @@ public class SysUserEntity {
@TableId(type = IdType.ASSIGN_UUID) @TableId(type = IdType.ASSIGN_UUID)
private String id; private String id;
private String name; private String name;
@TableField("user_name") @TableField("user_name")
private String userName; private String userName;
private String pwd; private String pwd;
@TableField(exist = false) @TableField(exist = false)
private String roleIds; private String roleIds;
@TableField(exist = false) @TableField(exist = false)
private List<SysRoleEntity> roles; private List<SysRoleEntity> roles;
private String accessLevel;
private Long createTimestamp; private Long createTimestamp;
} }

View File

@@ -1,7 +1,11 @@
package net.geedge.asw.module.sys.service.impl; package net.geedge.asw.module.sys.service.impl;
import cn.dev33.satoken.stp.StpUtil; 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 cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import net.geedge.asw.common.util.ASWException; import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.Constants; import net.geedge.asw.common.util.Constants;
@@ -13,9 +17,16 @@ import net.geedge.asw.module.sys.entity.SysMenuEntity;
import net.geedge.asw.module.sys.entity.SysRoleEntity; import net.geedge.asw.module.sys.entity.SysRoleEntity;
import net.geedge.asw.module.sys.entity.SysUserEntity; import net.geedge.asw.module.sys.entity.SysUserEntity;
import net.geedge.asw.module.sys.service.ISysAuthService; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -23,57 +34,90 @@ import java.util.stream.Collectors;
@Service @Service
public class SysAuthServiceImpl implements ISysAuthService { public class SysAuthServiceImpl implements ISysAuthService {
private static final Log log = Log.get(); private static final Log log = Log.get();
@Autowired @Autowired
private SysUserDao userDao; private SysUserDao userDao;
@Autowired
private SysRoleDao roleDao;
@Override @Autowired
public SysUserEntity login(String userName, String pwd) { private SysRoleDao roleDao;
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 @Autowired
public void logout() { private IWorkspaceService workspaceService;
StpUtil.logout();
}
/** @Autowired
* 获取登录用户权限 private IWorkspaceMemberService workspaceMemberService;
*/
@Override @Override
public Map<String, Object> userPermissions() { public SysUserEntity login(String userName, String pwd) {
Map<String, Object> result = T.MapUtil.newHashMap(); SysUserEntity userEntity = userDao
String userId = StpUtil.getLoginIdAsString(); .selectOne(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getUserName, userName));
List<SysRoleEntity> roleList = roleDao.findRoleByUserId(userId); if (T.ObjectUtil.isNull(userEntity)
result.put("roles", roleList); || !T.StrUtil.equals(userEntity.getPwd(), T.AesUtil.encrypt(pwd, Constants.AES_KEY))) {
// 组织 menu数据 log.warn("user login error, username: {}", userName);
List<SysMenuEntity> menuList = roleDao.findMenuByUserId(userId); throw ASWException.builder().rcode(RCode.SYS_USER_PWD_ERROR).build();
List<String> buttonList = menuList.stream().filter(menu -> T.StrUtil.equalsIgnoreCase(menu.getType(), "button")) }
.map(menu -> menu.getName()).collect(Collectors.toList()); StpUtil.login(userEntity.getId());
result.put("buttons", buttonList); log.info("user login success, userName: {}", userName);
//生成 menu tree结构 return userEntity;
Map<String, List<SysMenuEntity>> groupMap = menuList.stream() }
.filter(menu -> T.StrUtil.equalsIgnoreCase(menu.getType(), "menu"))
.collect(Collectors.groupingBy(SysMenuEntity::getPid)); @Override
menuList.forEach(menu -> { public void logout() {
menu.setChildren(groupMap.get(menu.getId())); StpUtil.logout();
}); }
List<SysMenuEntity> collect = menuList.stream().filter(menu -> T.StrUtil.isBlank(menu.getPid()))
.collect(Collectors.toList()); /**
result.put("menus", collect); * 获取登录用户权限
*/
return result; @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;
}
} }

View File

@@ -12,8 +12,7 @@ public class WorkbookConstant {
PACKAGE("package"), PACKAGE("package"),
SIGNATURE("signature"), SIGNATURE("signature"),
JOB("job"), JOB("job"),
PCAP("pcap"), PCAP("pcap");
DECODE_RECORD("decode_record");
private String value; private String value;

View File

@@ -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();
}
}

View File

@@ -1,10 +1,15 @@
package net.geedge.asw.module.workspace.dao; package net.geedge.asw.module.workspace.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity; import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper @Mapper
public interface WorkspaceDao extends BaseMapper<WorkspaceEntity> { public interface WorkspaceDao extends BaseMapper<WorkspaceEntity> {
List<WorkspaceEntity> queryList(Page page, Map<String, Object> params);
} }

View File

@@ -4,7 +4,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity; import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper @Mapper
public interface WorkspaceMemberDao extends BaseMapper<WorkspaceMemberEntity> { public interface WorkspaceMemberDao extends BaseMapper<WorkspaceMemberEntity> {
List<WorkspaceMemberEntity> queryList(String workspaceId);
} }

View File

@@ -1,9 +1,14 @@
package net.geedge.asw.module.workspace.entity; package net.geedge.asw.module.workspace.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import net.geedge.asw.module.sys.entity.SysRoleEntity;
import net.geedge.asw.module.sys.entity.SysUserEntity;
import java.util.List;
@Data @Data
@TableName("workspace") @TableName("workspace")
@@ -21,6 +26,13 @@ public class WorkspaceEntity {
private String createUserId; private String createUserId;
private String updateUserId; private String updateUserId;
private String workspaceId; @TableField(exist = false)
private SysUserEntity createUser;
@TableField(exist = false)
private SysUserEntity updateUser;
@TableField(exist = false)
private List<WorkspaceMemberEntity> members;
} }

View File

@@ -1,7 +1,12 @@
package net.geedge.asw.module.workspace.entity; package net.geedge.asw.module.workspace.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import net.geedge.asw.module.sys.entity.SysRoleEntity;
import net.geedge.asw.module.sys.entity.SysUserEntity;
import java.util.List;
@Data @Data
@TableName("workspace_member") @TableName("workspace_member")
@@ -14,4 +19,13 @@ public class WorkspaceMemberEntity {
private Long createTimestamp; private Long createTimestamp;
private String createUserId; private String createUserId;
@TableField(exist = false)
private SysUserEntity user;
@TableField(exist = false)
private SysRoleEntity role;
@TableField(exist = false)
private SysUserEntity createUser;
} }

View File

@@ -3,6 +3,13 @@ package net.geedge.asw.module.workspace.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity; import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
import java.util.List;
public interface IWorkspaceMemberService extends IService<WorkspaceMemberEntity>{ public interface IWorkspaceMemberService extends IService<WorkspaceMemberEntity>{
List<WorkspaceMemberEntity> queryList(String workspaceId);
List<WorkspaceMemberEntity> saveMember(String workspaceId ,List<WorkspaceMemberEntity> workspaces);
List<WorkspaceMemberEntity> updateMember(String workspaceId, List<WorkspaceMemberEntity> workspaces);
} }

View File

@@ -1,8 +1,18 @@
package net.geedge.asw.module.workspace.service; package net.geedge.asw.module.workspace.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity; import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import java.util.Map;
public interface IWorkspaceService extends IService<WorkspaceEntity>{ public interface IWorkspaceService extends IService<WorkspaceEntity>{
Page queryList(Map<String, Object> params);
WorkspaceEntity saveWorkspace(WorkspaceEntity workspace);
WorkspaceEntity updateWorkspace(WorkspaceEntity workspace);
void deleteWorkspace(String ids);
} }

View File

@@ -1,13 +1,78 @@
package net.geedge.asw.module.workspace.service.impl; package net.geedge.asw.module.workspace.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 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.common.util.VerifyUtil;
import net.geedge.asw.module.sys.service.ISysRoleService;
import net.geedge.asw.module.sys.service.ISysUserService;
import net.geedge.asw.module.workspace.dao.WorkspaceMemberDao; import net.geedge.asw.module.workspace.dao.WorkspaceMemberDao;
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity; import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
import net.geedge.asw.module.workspace.service.IWorkspaceMemberService; import net.geedge.asw.module.workspace.service.IWorkspaceMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
public class WorkspaceMemberServiceImpl extends ServiceImpl<WorkspaceMemberDao, WorkspaceMemberEntity> implements IWorkspaceMemberService { public class WorkspaceMemberServiceImpl extends ServiceImpl<WorkspaceMemberDao, WorkspaceMemberEntity> implements IWorkspaceMemberService {
@Autowired
private IWorkspaceMemberService workspaceMemberService;
@Autowired
private ISysUserService userService;
@Autowired
private ISysRoleService roleService;
@Override
public List<WorkspaceMemberEntity> queryList(String workspaceId) {
List<WorkspaceMemberEntity> list = this.baseMapper.queryList(workspaceId);
return list;
}
@Override
public List<WorkspaceMemberEntity> saveMember(String workspaceId, List<WorkspaceMemberEntity> workspaces) {
validateInfo(workspaceId, workspaces);
workspaceMemberService.saveBatch(workspaces);
List<WorkspaceMemberEntity> memberEntityList = workspaceMemberService.queryList(workspaceId);
return memberEntityList;
}
@Override
public List<WorkspaceMemberEntity> updateMember(String workspaceId, List<WorkspaceMemberEntity> workspaces) {
validateInfo(workspaceId, workspaces);
workspaceMemberService.remove(new LambdaQueryWrapper<WorkspaceMemberEntity>().eq(WorkspaceMemberEntity::getWorkspaceId, workspaceId));
workspaceMemberService.saveBatch(workspaces);
List<WorkspaceMemberEntity> memberEntityList = workspaceMemberService.queryList(workspaceId);
return memberEntityList;
}
private void validateInfo(String workspaceId, List<WorkspaceMemberEntity> workspaces) {
if (T.StrUtil.equalsIgnoreCase(workspaceId, "1")) {
throw new ASWException(RCode.WORKSPACE_BUILT_IN);
}
List<String> userIds = userService.list().stream().map(x -> x.getId()).toList();
List<String> roleIds = roleService.list().stream().map(x -> x.getId()).toList();
for (WorkspaceMemberEntity workspace : workspaces) {
VerifyUtil.is(workspace).notNull()
.and(workspace.getUserId()).notEmpty(RCode.USER_ID_CANNOT_EMPTY)
.and(workspace.getRoleId()).notEmpty(RCode.ROLE_ID_CANNOT_EMPTY);
if (!userIds.contains(workspace.getUserId())) {
throw new ASWException(RCode.USER_NOT_EXIST);
}
if (!roleIds.contains(workspace.getRoleId())) {
throw new ASWException(RCode.ROLE_NOT_EXIST);
}
}
workspaces.stream().forEach(x -> {
x.setWorkspaceId(workspaceId);
x.setCreateUserId(StpUtil.getLoginIdAsString());
x.setCreateTimestamp(System.currentTimeMillis());
});
}
} }

View File

@@ -1,13 +1,113 @@
package net.geedge.asw.module.workspace.service.impl; package net.geedge.asw.module.workspace.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 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.Constants;
import net.geedge.asw.common.util.RCode;
import net.geedge.asw.common.util.T;
import net.geedge.asw.module.workspace.dao.WorkspaceDao; import net.geedge.asw.module.workspace.dao.WorkspaceDao;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity; 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 net.geedge.asw.module.workspace.service.IWorkspaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Service @Service
public class WorkspaceServiceImpl extends ServiceImpl<WorkspaceDao, WorkspaceEntity> implements IWorkspaceService { public class WorkspaceServiceImpl extends ServiceImpl<WorkspaceDao, WorkspaceEntity> implements IWorkspaceService {
@Autowired
private IWorkspaceService workspaceService;
@Autowired
private IWorkspaceMemberService workspaceMemberService;
@Override
public Page queryList(Map<String, Object> params) {
Page page = T.PageUtil.getPage(params);
List<WorkspaceEntity> workspaceEntityList = this.getBaseMapper().queryList(page, params);
page.setRecords(workspaceEntityList);
return page;
}
@Override
@Transactional(rollbackFor = Exception.class)
public WorkspaceEntity saveWorkspace(WorkspaceEntity workspace) {
this.validateWorkspaceInfo(workspace, false);
workspace.setCreateUserId(StpUtil.getLoginIdAsString());
workspace.setUpdateUserId(StpUtil.getLoginIdAsString());
workspace.setCreateTimestamp(System.currentTimeMillis());
workspace.setUpdateTimestamp(System.currentTimeMillis());
workspaceService.save(workspace);
if (T.CollectionUtil.isNotEmpty(workspace.getMembers())) {
List<WorkspaceMemberEntity> members = workspace.getMembers();
members.stream().forEach(x -> {
x.setWorkspaceId(workspace.getId());
x.setCreateTimestamp(System.currentTimeMillis());
x.setCreateUserId(StpUtil.getLoginIdAsString());
});
workspaceMemberService.saveBatch(members);
}
return workspace;
}
@Override
@Transactional(rollbackFor = Exception.class)
public WorkspaceEntity updateWorkspace(WorkspaceEntity workspace) {
this.validateWorkspaceInfo(workspace, true);
workspace.setUpdateUserId(StpUtil.getLoginIdAsString());
workspace.setUpdateTimestamp(System.currentTimeMillis());
workspaceService.updateById(workspace);
if (T.CollectionUtil.isNotEmpty(workspace.getMembers())) {
List<WorkspaceMemberEntity> members = workspace.getMembers();
members.stream().forEach(x -> {
x.setWorkspaceId(workspace.getId());
x.setCreateTimestamp(System.currentTimeMillis());
x.setCreateUserId(StpUtil.getLoginIdAsString());
});
workspaceMemberService.remove(new LambdaQueryWrapper<WorkspaceMemberEntity>().eq(WorkspaceMemberEntity::getWorkspaceId, workspace.getId()));
workspaceMemberService.saveBatch(members);
}
return workspace;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteWorkspace(String ids) {
List workspaceIds = Arrays.asList(ids.split(","));
if (workspaceIds.contains("1")) {
throw new ASWException(RCode.WORKSPACE_CANNOT_DELETE);
}
workspaceService.removeBatchByIds(workspaceIds);
workspaceMemberService.remove(new LambdaQueryWrapper<WorkspaceMemberEntity>().in(WorkspaceMemberEntity::getWorkspaceId, workspaceIds));
}
private void validateWorkspaceInfo(WorkspaceEntity workspace, boolean isUpdate) {
if (!Constants.VISIBILITY_LIST.contains(workspace.getVisibility())) {
throw new ASWException(RCode.WORKSPACE_VISIBILITY_ERROR);
}
if (T.StrUtil.equals(workspace.getVisibility(), "private") && T.CollectionUtil.isEmpty(workspace.getMembers())) {
throw new ASWException(RCode.WORKSPACE_USER_CANNOT_EMPTY);
}
List<WorkspaceEntity> list = workspaceService.list(new LambdaQueryWrapper<WorkspaceEntity>().eq(WorkspaceEntity::getName, workspace.getName()));
if (!isUpdate && T.CollectionUtil.isNotEmpty(list)) {
throw new ASWException(RCode.WORKSPACE_ALREADY_EXISTS);
}
if (isUpdate && T.CollectionUtil.isNotEmpty(list) && T.StrUtil.equals(workspace.getId(), list.getFirst().getId())) {
throw new ASWException(RCode.WORKSPACE_ALREADY_EXISTS);
}
}
} }

View File

@@ -35,7 +35,20 @@ spring:
enabled: true enabled: true
main: main:
allow-circular-references: true allow-circular-references: true
feign:
client:
config:
default: # 这里用default就是全局配置如果是写服务名称则是针对某个微服务的配置
connectTimeout: 5000
readTimeout: 5000
loggerLevel: BASIC # 日志级别 NONE|BASIC|HEADERS|FULL
httpclient:
enabled: true
max-connections: 200 # httpclient处理的最大连接数量
max-connections-per-route: 50 # 单个路径连接的最大数量
connection-timeout: 2000 # 超时等待
server: server:
# port: 2023 # port: 2023
servlet: servlet:

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.geedge.asw.module.app.dao.ApplicationDao">
<resultMap id="appResult" type="net.geedge.asw.module.app.entity.ApplicationEntity">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="longName" column="long_name"/>
<result property="properties" column="properties"/>
<result property="description" column="description"/>
<result property="surrogates" column="surrogates"/>
<result property="createTimestamp" column="create_timestamp"/>
<result property="updateTimestamp" column="update_timestamp"/>
<result property="createUserId" column="create_user_id"/>
<result property="updateUserId" column="update_user_id"/>
<result property="workspaceId" column="workspace_id"/>
<result property="opVersion" column="op_version"/>
<association property="createUser" columnPrefix="cu_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
<association property="updateUser" columnPrefix="uu_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
</resultMap>
<select id="queryList" resultMap="appResult">
SELECT
app.*,
cu.id as cu_id,
cu.name as cu_name,
uu.id as uu_id,
uu.id as uu_name
FROM
application app
left join sys_user cu on app.create_user_id = cu.id
left join sys_user uu on app.update_user_id = uu.id
<where>
<if test="params.ids != null and params.ids != ''">
app.id in
<foreach item="id" collection="params.ids.split(',')" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="params.q != null and params.q != ''">
AND ( locate(#{params.q}, app.name) OR locate(#{params.q}, app.description) )
</if>
<if test="params.id != null and params.id != ''">
AND app.id = #{params.id}
</if>
<if test="params.workspaceId != null and params.workspaceId != ''">
AND app.workspace_id = #{params.workspaceId}
</if>
</where>
<if test="params.orderBy == null or params.orderBy == ''">
ORDER BY app.id
</if>
</select>
<select id="queryLogList" resultMap="appResult">
SELECT
app.*,
cu.id as cu_id,
cu.name as cu_name,
uu.id as uu_id,
uu.id as uu_name
FROM
(select * from application union select * from application_log) app
left join sys_user cu on app.create_user_id = cu.id
left join sys_user uu on app.update_user_id = uu.id
<where>
<if test="id != null and id != ''">
AND app.id = #{id}
</if>
<if test="workspaceId != null and workspaceId != ''">
AND app.workspace_id = #{workspaceId}
</if>
</where>
ORDER BY app.op_version DESC
</select>
<select id="compare" resultMap="appResult">
SELECT
app.*,
cu.id as cu_id,
cu.name as cu_name,
uu.id as uu_id,
uu.id as uu_name
FROM
(select * from application union select * from application_log ) app
left join sys_user cu on app.create_user_id = cu.id
left join sys_user uu on app.update_user_id = uu.id
<where>
<if test="params.versions != null and params.versions != ''">
AND app.op_version in
<foreach item="version" collection="params.versions" separator="," open="(" close=")">
#{version}
</foreach>
</if>
<if test="params.id != null and params.id != ''">
AND app.id = #{params.id}
</if>
<if test="params.workspaceId != null and params.workspaceId != ''">
AND app.workspace_id = #{params.workspaceId}
</if>
</where>
</select>
</mapper>

View File

@@ -6,16 +6,10 @@
<resultMap type="net.geedge.asw.module.runner.entity.PcapEntity" id="pcapResultMap"> <resultMap type="net.geedge.asw.module.runner.entity.PcapEntity" id="pcapResultMap">
<id property="id" column="id"/> <id property="id" column="id"/>
<result property="name" column="name"/> <result property="name" column="name"/>
<result property="tags" column="tags"/>
<result property="description" column="description"/> <result property="description" column="description"/>
<result property="path" column="path"/> <result property="path" column="path"/>
<result property="size" column="size"/> <result property="size" column="size"/>
<result property="connections" column="connections"/>
<result property="hosts" column="hosts"/>
<result property="md5" column="md5"/> <result property="md5" column="md5"/>
<result property="connectionTimeFirst" column="connection_time_first"/>
<result property="connectionTimeLast" column="connection_time_last"/>
<result property="protocols" column="protocols"/>
<result property="status" column="status"/> <result property="status" column="status"/>
<result property="createTimestamp" column="create_timestamp"/> <result property="createTimestamp" column="create_timestamp"/>
<result property="createUserId" column="create_user_id"/> <result property="createUserId" column="create_user_id"/>
@@ -81,6 +75,10 @@
<foreach item="id" collection="params.ids.split(',')" separator="," open="(" close=")">#{id}</foreach> <foreach item="id" collection="params.ids.split(',')" separator="," open="(" close=")">#{id}</foreach>
</if> </if>
<if test="params.q != null and params.q != ''">
AND ( locate(#{params.q}, pcap.name) OR locate(#{params.q}, pcap.description) )
</if>
<if test="params.jobIds != null and params.jobIds != ''"> <if test="params.jobIds != null and params.jobIds != ''">
AND job.id in AND job.id in
<foreach item="id" collection="params.jobIds.split(',')" separator="," open="(" close=")">#{id}</foreach> <foreach item="id" collection="params.jobIds.split(',')" separator="," open="(" close=")">#{id}</foreach>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.geedge.asw.module.workspace.dao.WorkspaceDao">
<resultMap id="workspaceResultMap" type="net.geedge.asw.module.workspace.entity.WorkspaceEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="tags" column="tags"/>
<result property="visibility" column="visibility"/>
<result property="description" column="description"/>
<result property="createTimestamp" column="create_timestamp"/>
<result property="updateTimestamp" column="update_timestamp"/>
<result property="createUserId" column="create_user_id"/>
<result property="updateUserId" column="update_user_id"/>
<association property="createUser" columnPrefix="cu_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
<association property="updateUser" columnPrefix="uu_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
</resultMap>
<select id="queryList" resultMap="workspaceResultMap">
SELECT
ws.*,
cu.id AS cu_id,
cu.name AS cu_name,
uu.id AS uu_id,
uu.name AS uu_name
FROM
workspace ws
LEFT JOIN sys_user cu ON ws.create_user_id = cu.id
LEFT JOIN sys_user uu ON ws.update_user_id = uu.id
<where>
<if test="params.ids != null and params.ids != ''">
ws.id in
<foreach item="id" collection="params.ids.split(',')" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="params.q != null and params.q != ''">
AND ( locate(#{params.q}, ws.name) OR locate(#{params.q}, ws.description) OR locate(#{params.q},
ws.tags) )
</if>
</where>
<if test="params.orderBy == null or params.orderBy == ''">
ORDER BY ws.id
</if>
</select>
</mapper>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="net.geedge.asw.module.workspace.dao.WorkspaceMemberDao">
<resultMap id="workspaceMemberResultMap" type="net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity">
<result property="workspaceId" column="workspace_id"/>
<result property="userId" column="user_id"/>
<result property="roleId" column="role_id"/>
<result property="createTimestamp" column="create_timestamp"/>
<result property="createUserId" column="create_user_id"/>
<association property="createUser" columnPrefix="cu_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
<association property="user" columnPrefix="su_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
<association property="role" columnPrefix="sr_" javaType="net.geedge.asw.module.sys.entity.SysRoleEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
</resultMap>
<select id="queryList" resultMap="workspaceMemberResultMap">
SELECT
wm.*,
cu.id AS cu_id,
cu.name AS cu_name,
su.id AS su_id,
su.name AS su_name,
sr.id AS sr_id,
sr.name AS sr_name
FROM
workspace_member wm
LEFT JOIN sys_user cu ON wm.create_user_id = cu.id
LEFT JOIN sys_user su ON wm.user_id = su.id
LEFT JOIN sys_role sr ON wm.role_id = sr.id
<where>
<if test="workspaceId != null and workspaceId != ''">
wm.workspace_id = #{workspaceId}
</if>
</where>
</select>
</mapper>

View File

@@ -51,6 +51,44 @@ INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (59, '202002', 'PACKAGE_DESCRIPTION_CANNOT_EMPTY', '安装包描述信息不能为空', 'zh', '', 'admin', 1719280800000); INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (59, '202002', 'PACKAGE_DESCRIPTION_CANNOT_EMPTY', '安装包描述信息不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (61, '401001', 'WORKSPACE_ID_CANNOT_EMPTY', 'workspace id cannot be empty', 'en', '', 'admin', 1719280800000); INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (61, '401001', 'WORKSPACE_ID_CANNOT_EMPTY', 'workspace id cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (63, '401001', 'WORKSPACE_ID_CANNOT_EMPTY', '工作空间ID不能为空', 'zh', '', 'admin', 1719280800000); INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (63, '401001', 'WORKSPACE_ID_CANNOT_EMPTY', '工作空间ID不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (65, '401002', 'WORKSPACE_NAME_CANNOT_EMPTY', 'workspace name cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (67, '401002', 'WORKSPACE_NAME_CANNOT_EMPTY', '工作空间名称不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (69, '401003', 'WORKSPACE_VISIBILITY_CANNOT_EMPTY', 'workspace visibility cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (71, '401003', 'WORKSPACE_VISIBILITY_CANNOT_EMPTY', '工作空间可见性不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (73, '401004', 'WORKSPACE_USER_CANNOT_EMPTY', 'workspace user cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (75, '401004', 'WORKSPACE_USER_CANNOT_EMPTY', '工作空间用户不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (77, '401005', 'WORKSPACE_ALREADY_EXISTS', 'workspace already exists', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (79, '401005', 'WORKSPACE_ALREADY_EXISTS', '工作空间已存在', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (81, '401006', 'WORKSPACE_MEMBER_CANNOT_EMPTY', 'workspace member cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (83, '401006', 'WORKSPACE_MEMBER_CANNOT_EMPTY', '工作空间成员不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (85, '401007', 'WORKSPACE_CANNOT_DELETE', 'Built-in workspace cannot be deleted', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (87, '401007', 'WORKSPACE_CANNOT_DELETE', '内置工作空间不能删除', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (89, '100009', 'USER_ID_CANNOT_EMPTY', 'user id cannot be empty ', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (91, '100009', 'USER_ID_CANNOT_EMPTY', '用户 ID 不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (93, '201002', 'APP_NAME_CANNOT_EMPTY', 'application name cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (95, '201002', 'APP_NAME_CANNOT_EMPTY', '应用程序名称不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (97, '201003', 'APP_LONGNAME_CANNOT_EMPTY', 'application longName cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (99, '201003', 'APP_LONGNAME_CANNOT_EMPTY', '应用程序全称不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (101, '201004', 'APP_PROPERTIES_CANNOT_EMPTY', 'application properties cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (103, '201004', 'APP_PROPERTIES_CANNOT_EMPTY', '应用程序属性不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (105, '201005', 'APP_SURROGATES_CANNOT_EMPTY', 'application surrogates cannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (107, '201005', 'APP_SURROGATES_CANNOT_EMPTY', '应用程序代理不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (109, '201006', 'APP_DESCRIPTION_CANNOT_EMPTY', 'application descriptioncannot be empty', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (111, '201006', 'APP_DESCRIPTION_CANNOT_EMPTY', '应用描述不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (113, '201007', 'APP_DUPLICATE_RECORD', 'application duplicate record', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (115, '201007', 'APP_DUPLICATE_RECORD', '应用程序重复记录', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (117, '201008', 'APP_NOT_EXIST', 'application does not exist', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (119, '201008', 'APP_NOT_EXIST', '应用程序不存在', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (121, '401008', 'WORKSPACE_VISIBILITY_ERROR', 'workspace visibility error', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (123, '401008', 'WORKSPACE_VISIBILITY_ERROR', '工作空间可见性错误', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (125, '401009', 'WORKSPACE_BUILT_IN', 'Built-in workspace cannot be update', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (127, '401009', 'WORKSPACE_BUILT_IN', '内置工作空间不可修改', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (129, '100010', 'ROLE_ID_CANNOT_EMPTY', 'role id cannot be empty ', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (131, '100010', 'ROLE_ID_CANNOT_EMPTY', '权限 ID 不能为空', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (133, '100011', 'USER_NOT_EXIST', 'user does not exist', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (135, '100011', 'USER_NOT_EXIST', '用户不存在', 'zh', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (137, '100012', 'ROLE_NOT_EXIST', 'role does not exist', 'en', '', 'admin', 1719280800000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (139, '100012', 'ROLE_NOT_EXIST', '权限不存在', 'zh', '', 'admin', 1719280800000);
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,40 @@
/**
* 重置 SYS_MENU 数据
*/
TRUNCATE sys_menu;
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('1000', 'workbooks', 'overall.workbooks', '0', 'menu', '', '/workbooks', 'asw-icon icon-Workbooks', 0, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('1001', 'workbook_view', 'buttons.view', '1000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2000', 'applications', 'overall.applications', '0', 'menu', '', '/applications', 'asw-icon icon-Applications', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2001', 'application_view', 'buttons.view', '2000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2002', 'application_add', 'buttons.add', '2000', 'button', '', '', '', 2, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2003', 'application_edit', 'buttons.edit', '2000', 'button', '', '', '', 3, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2004', 'application_delete', 'buttons.delete', '2000', 'button', '', '', '', 4, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2005', 'application_history', 'buttons.history', '2000', 'button', '', '', '', 5, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2006', 'application_compare', 'buttons.compare', '2000', 'button', '', '', '', 6, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('2007', 'application_restore', 'buttons.restore', '2000', 'button', '', '', '', 7, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3000', 'pcaps', 'overall.pcaps', '0', 'menu', '', '/pcaps', 'asw-icon icon-Pcaps', 2, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3001', 'pacp_view', 'buttons.view', '3000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3002', 'pacp_upload', 'buttons.upload', '3000', 'button', '', '', '', 2, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3003', 'pacp_delete', 'buttons.delete', '3000', 'button', '', '', '', 3, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3004', 'pacp_parse', 'buttons.parse', '3000', 'button', '', '', '', 4, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('3005', 'pacp_analyze', 'buttons.analyze', '3000', 'button', '', '', '', 5, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('4000', 'packages', 'overall.packages', '0', 'menu', '', '/packages', 'asw-icon icon-Packages', 3, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('4001', 'package_view', 'buttons.view', '4000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5000', 'jobs', 'overall.jobs', '0', 'menu', '', '/jobs', 'asw-icon icon-Jobs', 4, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5001', 'job_view', 'buttons.view', '5000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5002', 'job_add', 'buttons.add', '5000', 'button', '', '', '', 2, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5003', 'job_delete', 'buttons.delete', '5000', 'button', '', '', '', 3, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('6000', 'playbooks', 'overall.playbooks', '0', 'menu', '', '/playbooks', 'asw-icon icon-Playbooks', 5, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('6001', 'playbook_view', 'buttons.view', '6000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('7000', 'runners', 'overall.runners', '0', 'menu', '', '/runners', 'asw-icon icon-Runners', 6, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('7001', 'runner_view', 'buttons.view', '7000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('1', 'workspace_add', 'buttons.add', '0', 'button', '', '', '', 1, 1722478572000, 1);

View File

@@ -0,0 +1,51 @@
/**
* 先清空 sys_role_menu 表中 admin&common 相关数据,再导入
*/
delete from sys_role_menu where role_id in ('admin' ,'common');
-- admin
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '1000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '1001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2002');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2003');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2004');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2005');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2006');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '2007');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3002');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3003');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3004');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '3005');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '4000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '4001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '5000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '5001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '5002');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '5003');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '6000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '6001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '7000');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '7001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('admin', '1');
-- common
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '1001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '2001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '3001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '4001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '5001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '6001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '7001');
INSERT INTO `sys_role_menu`(`role_id`, `menu_id`) VALUES ('common', '1');

View File

@@ -8,13 +8,14 @@ CREATE TABLE `sys_user` (
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`user_name` varchar(255) NOT NULL, `user_name` varchar(255) NOT NULL,
`pwd` varchar(255) NOT NULL, `pwd` varchar(255) NOT NULL,
`access_level` varchar(255) NOT NULL,
`create_timestamp` bigint(20) NOT NULL, `create_timestamp` bigint(20) NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_name` (`user_name`) USING BTREE, UNIQUE KEY `idx_user_name` (`user_name`) USING BTREE,
KEY `idx_name` (`name`) USING BTREE KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加内置用户
INSERT INTO `sys_user`(`id`, `name`, `user_name`, `pwd`, `create_timestamp`) VALUES ('admin', 'admin', 'admin', 'ad9d757e620d5d9cd8e32c3dbcf37525', UNIX_TIMESTAMP(NOW())*1000); INSERT INTO `sys_user`(`id`, `name`, `user_name`, `pwd`, `access_level`, `create_timestamp`) VALUES ('admin', 'admin', 'admin', 'ad9d757e620d5d9cd8e32c3dbcf37525', 'administrator', UNIX_TIMESTAMP(NOW())*1000);
/** /**
* 1、新增 sys_role 表 * 1、新增 sys_role 表
@@ -35,6 +36,10 @@ CREATE TABLE `sys_role` (
KEY `idx_name` (`name`) USING BTREE KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加内置角色
INSERT INTO `sys_role` (`id`, `name`, `i18n`, `remark`, `build_in`, `create_timestamp`) VALUES ('admin', 'admin', 'admin', 'admin', 1, UNIX_TIMESTAMP(NOW())*1000);
INSERT INTO `sys_role` (`id`, `name`, `i18n`, `remark`, `build_in`, `create_timestamp`) VALUES ('common', 'common', 'common', 'common', 1, UNIX_TIMESTAMP(NOW())*1000);
DROP TABLE IF EXISTS `sys_menu`; DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` ( CREATE TABLE `sys_menu` (
@@ -59,14 +64,14 @@ CREATE TABLE `sys_user_role` (
`role_id` varchar(64) NOT NULL `role_id` varchar(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `sys_user_role`(`user_id`, `role_id`) VALUES ('admin', 'admin');
DROP TABLE IF EXISTS `sys_role_menu`; DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` ( CREATE TABLE `sys_role_menu` (
`menu_id` varchar(64) NOT NULL, `menu_id` varchar(64) NOT NULL,
`role_id` varchar(64) NOT NULL `role_id` varchar(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加内置角色
INSERT INTO `sys_role` (`id`, `name`, `i18n`, `remark`, `build_in`, `create_timestamp`) VALUES ('admin', 'admin', 'admin', 'admin', 1, UNIX_TIMESTAMP(NOW())*1000);
/** /**
* 1、新增 sys_config 表 * 1、新增 sys_config 表
@@ -217,16 +222,10 @@ DROP TABLE IF EXISTS `pcap`;
CREATE TABLE `pcap` ( CREATE TABLE `pcap` (
`id` varchar(64) NOT NULL COMMENT '主键', `id` varchar(64) NOT NULL COMMENT '主键',
`name` varchar(256) NOT NULL DEFAULT '' COMMENT '文件名称', `name` varchar(256) NOT NULL DEFAULT '' COMMENT '文件名称',
`tags` varchar(256) NOT NULL DEFAULT '' COMMENT '标签',
`description` text NOT NULL DEFAULT '' COMMENT '描述信息', `description` text NOT NULL DEFAULT '' COMMENT '描述信息',
`path` varchar(64) NOT NULL DEFAULT '' COMMENT 'PCAP文件路径', `path` varchar(64) NOT NULL DEFAULT '' COMMENT 'PCAP文件路径',
`size` bigint(20) NOT NULL DEFAULT 0 COMMENT '文件大小', `size` bigint(20) NOT NULL DEFAULT 0 COMMENT '文件大小',
`connections` bigint(20) NOT NULL DEFAULT 0 COMMENT '连接数量',
`hosts` bigint(20) NOT NULL DEFAULT 0 COMMENT 'IP数量',
`md5` varchar(64) NOT NULL DEFAULT '' COMMENT '摘要值,根据文件md5值判断是否已上存在存在则响应当前id', `md5` varchar(64) NOT NULL DEFAULT '' COMMENT '摘要值,根据文件md5值判断是否已上存在存在则响应当前id',
`connection_time_first` bigint(20) NOT NULL DEFAULT -1 COMMENT '连接开始时间',
`connection_time_last` bigint(20) NOT NULL DEFAULT -1 COMMENT '连接结束时间',
`protocols` varchar(64) NOT NULL DEFAULT '' COMMENT '包含的协议,多个逗号分隔',
`status` varchar(64) NOT NULL DEFAULT '' COMMENT '状态,可选值 UploadedAnalyzingCompleted', `status` varchar(64) NOT NULL DEFAULT '' COMMENT '状态,可选值 UploadedAnalyzingCompleted',
`create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳', `create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳',
`create_user_id` varchar(64) NOT NULL COMMENT '创建人', `create_user_id` varchar(64) NOT NULL COMMENT '创建人',
@@ -234,23 +233,6 @@ CREATE TABLE `pcap` (
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_name` (`name`) USING BTREE, KEY `idx_name` (`name`) USING BTREE,
KEY `idx_md5` (`md5`) USING BTREE, KEY `idx_md5` (`md5`) USING BTREE,
KEY `idx_tags` (`tags`) USING BTREE,
KEY `idx_workspace_id` (`workspace_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/**
* 新增 decode_record 表
*/
DROP TABLE IF EXISTS `decode_record`;
CREATE TABLE `decode_record` (
`id` varchar(64) NOT NULL COMMENT '主键',
`pcap_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'PCAP文件ID',
`stream_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '流ID',
`stream_attributes` text NOT NULL DEFAULT '' COMMENT '流属性',
`workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_pcap_id` (`pcap_id`) USING BTREE,
KEY `idx_stream_id` (`stream_id`) USING BTREE,
KEY `idx_workspace_id` (`workspace_id`) USING BTREE KEY `idx_workspace_id` (`workspace_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -271,12 +253,34 @@ CREATE TABLE `application` (
`create_user_id` varchar(64) NOT NULL COMMENT '创建人', `create_user_id` varchar(64) NOT NULL COMMENT '创建人',
`update_user_id` varchar(64) NOT NULL COMMENT '更新人', `update_user_id` varchar(64) NOT NULL COMMENT '更新人',
`workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID', `workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID',
`op_version` int(10) NOT NULL DEFAULT 1 COMMENT '版本号',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_name` (`name`) USING BTREE, KEY `idx_name` (`name`) USING BTREE,
KEY `idx_long_name` (`long_name`) USING BTREE, KEY `idx_long_name` (`long_name`) USING BTREE,
KEY `idx_workspace_id` (`workspace_id`) USING BTREE KEY `idx_workspace_id` (`workspace_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/**
* 新增 application_log 表
*/
DROP TABLE IF EXISTS `application_log`;
CREATE TABLE `application_log` (
`id` varchar(64) NOT NULL COMMENT '主键',
`name` varchar(256) NOT NULL DEFAULT '' COMMENT '应用名称',
`long_name` varchar(256) NOT NULL DEFAULT '' COMMENT '应用全称',
`properties` text NOT NULL DEFAULT '' COMMENT '应用数据',
`description` text NOT NULL DEFAULT '' COMMENT '描述信息',
`surrogates` text NOT NULL DEFAULT '' COMMENT '',
`create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳',
`update_timestamp` bigint(20) NOT NULL COMMENT '更新时间戳',
`create_user_id` varchar(64) NOT NULL COMMENT '创建人',
`update_user_id` varchar(64) NOT NULL COMMENT '更新人',
`workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID',
`op_version` int(10) NOT NULL DEFAULT 1 COMMENT '版本号',
UNIQUE INDEX `index_id_version` (`id`, `op_version`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/** /**
* 新增 package 表 * 新增 package 表
*/ */
@@ -359,7 +363,7 @@ DROP TABLE IF EXISTS `workbook_resource`;
CREATE TABLE `workbook_resource` ( CREATE TABLE `workbook_resource` (
`id` varchar(64) NOT NULL COMMENT '主键', `id` varchar(64) NOT NULL COMMENT '主键',
`workbook_id` varchar(64) NOT NULL COMMENT 'workbook ID', `workbook_id` varchar(64) NOT NULL COMMENT 'workbook ID',
`resource_type` varchar(64) NOT NULL COMMENT '资源类型 可选值package,signature,job,pcap,decode_record', `resource_type` varchar(64) NOT NULL COMMENT '资源类型 可选值package,signature,job,pcap',
`resource_id` varchar(64) NOT NULL COMMENT '资源id', `resource_id` varchar(64) NOT NULL COMMENT '资源id',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -383,6 +387,8 @@ CREATE TABLE `workspace` (
KEY `idx_name` (`name`) USING BTREE KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `workspace` (`id`, `name`, `tags`, `visibility`, `description`, `create_timestamp`, `update_timestamp`, `create_user_id`, `update_user_id`) VALUES ('1', 'default', '', 'public', '', 1722482392000, 1722482392000, 'admin', 'admin');
DROP TABLE IF EXISTS `workspace_member`; DROP TABLE IF EXISTS `workspace_member`;
CREATE TABLE `workspace_member` ( CREATE TABLE `workspace_member` (
`workspace_id` varchar(64) NOT NULL, `workspace_id` varchar(64) NOT NULL,