diff --git a/build.gradle b/build.gradle index 94f59e9..14c0d8a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' diff --git a/src/main/java/com/realtime/protection/configuration/entity/defense/template/Template.java b/src/main/java/com/realtime/protection/configuration/entity/defense/template/Template.java new file mode 100644 index 0000000..80dd2ee --- /dev/null +++ b/src/main/java/com/realtime/protection/configuration/entity/defense/template/Template.java @@ -0,0 +1,36 @@ +package com.realtime.protection.configuration.entity.defense.template; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class Template { + @JsonProperty("template_id") + private Integer templateId; + + @JsonProperty("template_name") + @NotNull(message = "template name should not be empty") + private String templateName; + + @JsonProperty("template_elements") + private String[] templateElements; + + @JsonProperty("default_op") + @NotNull(message = "default_op should not be empty") + private String defaultOp; + + private boolean hasProtectObjectIP; + + private boolean hasProtectObjectPort; + + private boolean hasPeerIP; + + private boolean hasPeerPort; + + private boolean hasProtocol; + + private boolean hasURL; + + private boolean hasDNS; +} diff --git a/src/main/java/com/realtime/protection/configuration/entity/task/Task.java b/src/main/java/com/realtime/protection/configuration/entity/task/Task.java new file mode 100644 index 0000000..6952169 --- /dev/null +++ b/src/main/java/com/realtime/protection/configuration/entity/task/Task.java @@ -0,0 +1,69 @@ +package com.realtime.protection.configuration.entity.task; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class Task { + @JsonProperty("task_id") + private Integer taskId; + + @JsonProperty("task_name") + @NotNull(message = "task_name should not be empty") + private String taskName; + + @JsonProperty("task_start_time") + @NotNull(message = "task_start_time should not be empty") + private LocalDateTime taskStartTime; + + @JsonProperty("task_end_time") + @NotNull(message = "task_end_time should not be empty") + private LocalDateTime taskEndTime; + + @JsonProperty("task_create_time") + private LocalDateTime taskCreateTime; + + @JsonProperty("task_modify_time") + private LocalDateTime taskModifyTime; + + @JsonProperty("task_type") + @NotNull(message = "task_type should not be empty") + private String taskType; + + @JsonProperty("task_act") + @NotNull(message = "task_act should not be empty") + private String taskAct; + + // These three attributes will be gained by user in the future + // ----------------------------------------------------------- + @JsonProperty("task_create_username") + @NotNull(message = "task_create_username should not be empty") + private String taskCreateUsername; + + @JsonProperty("task_create_depart") + @NotNull(message = "task_create_depart should not be empty") + private String taskCreateDepart; + + @JsonProperty("task_create_userid") + @NotNull(message = "task_create_userid should not be empty") + private Integer taskCreateUserId; + // ----------------------------------------------------------- + + @JsonProperty("static_rule_ids") + private Integer[] staticRuleIds; + + @JsonProperty("dynamic_rule_ids") + private Integer[] dynamicRuleIds; + + @JsonProperty("protect_object_ids") + private Integer[] protectObjectIds; + + @JsonProperty("task_status") + private Integer taskStatus; + + @JsonProperty("task_audit_status") + private Integer taskAuditStatus; +} diff --git a/src/main/java/com/realtime/protection/configuration/exception/GlobalExceptionHandler.java b/src/main/java/com/realtime/protection/configuration/exception/GlobalExceptionHandler.java index 3dc03ce..26ecf6a 100644 --- a/src/main/java/com/realtime/protection/configuration/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/realtime/protection/configuration/exception/GlobalExceptionHandler.java @@ -1,18 +1,49 @@ package com.realtime.protection.configuration.exception; +import cn.dev33.satoken.exception.NotLoginException; import com.realtime.protection.configuration.response.ResponseResult; +import org.apache.ibatis.exceptions.PersistenceException; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.core.annotation.Order; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import java.util.stream.Collectors; + @RestControllerAdvice public class GlobalExceptionHandler { - @ExceptionHandler + @Order(3) + @ExceptionHandler(value = Exception.class) public ResponseResult handleGlobalException(Exception e) { - - - - return ResponseResult.error().setMessage(e.getMessage()); } + + @Order(2) + @ExceptionHandler(value = NotLoginException.class) + public ResponseResult handleNotLoginException(NotLoginException e) { + return new ResponseResult( + 400, + e.getMessage() + ); + } + + @Order(2) + @ExceptionHandler(value = PersistenceException.class) + public ResponseResult handleSQLException() { + return new ResponseResult( + 400, + "please check the integrity of the data. check if the json data exists in the database"); + } + + @Order(2) + @ExceptionHandler(value = MethodArgumentNotValidException.class) + public ResponseResult handleBindException(MethodArgumentNotValidException e) { + return new ResponseResult( + 400, + e.getBindingResult().getAllErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining()) + ); + } } diff --git a/src/main/java/com/realtime/protection/server/defense/template/TemplateController.java b/src/main/java/com/realtime/protection/server/defense/template/TemplateController.java new file mode 100644 index 0000000..c843abb --- /dev/null +++ b/src/main/java/com/realtime/protection/server/defense/template/TemplateController.java @@ -0,0 +1,43 @@ +package com.realtime.protection.server.defense.template; + +import com.realtime.protection.configuration.entity.defense.template.Template; +import com.realtime.protection.configuration.response.ResponseResult; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/deftac") +public class TemplateController { + + private final TemplateService templateService; + + public TemplateController(TemplateService templateService) { + this.templateService = templateService; + } + + @PostMapping("/new") + public ResponseResult newTemplate(@RequestBody @Valid Template template) { + Integer templateId; + try { + templateId = templateService.newTemplate(template); + } catch (IllegalArgumentException e) { + return new ResponseResult(400, "Illegal Argument in template_elements or default_op") + .setData("template_id", null) + .setData("success", false); + } + + + if (templateId > 0) { + return ResponseResult.ok() + .setData("template_id", templateId) + .setData("success", true); + } + + return ResponseResult.error() + .setData("template_id", null) + .setData("success", false); + } +} diff --git a/src/main/java/com/realtime/protection/server/defense/template/TemplateMapper.java b/src/main/java/com/realtime/protection/server/defense/template/TemplateMapper.java new file mode 100644 index 0000000..e794ce6 --- /dev/null +++ b/src/main/java/com/realtime/protection/server/defense/template/TemplateMapper.java @@ -0,0 +1,11 @@ +package com.realtime.protection.server.defense.template; + +import com.realtime.protection.configuration.entity.defense.template.Template; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface TemplateMapper { + + void newTemplate(@Param("template") Template template); +} diff --git a/src/main/java/com/realtime/protection/server/defense/template/TemplateService.java b/src/main/java/com/realtime/protection/server/defense/template/TemplateService.java new file mode 100644 index 0000000..2c057c6 --- /dev/null +++ b/src/main/java/com/realtime/protection/server/defense/template/TemplateService.java @@ -0,0 +1,45 @@ +package com.realtime.protection.server.defense.template; + +import com.realtime.protection.configuration.entity.defense.template.Template; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +@Service +public class TemplateService { + + private final TemplateMapper templateMapper; + + private final String[] permittedOps = new String[]{"阻断", "清洗", "篡改", "反制"}; + + public TemplateService(TemplateMapper templateMapper) { + this.templateMapper = templateMapper; + } + + public Integer newTemplate(Template template) throws IllegalArgumentException { + if (!Arrays.asList(permittedOps).contains(template.getDefaultOp())) { + throw new IllegalArgumentException(); + } + + for (String choice : template.getTemplateElements()) { + switch (choice) { + case "防护对象IP" -> template.setHasProtectObjectIP(true); + case "防护对象端口" -> template.setHasProtectObjectPort(true); + case "对端IP" -> template.setHasPeerIP(true); + case "对端端口" -> template.setHasPeerPort(true); + case "协议" -> template.setHasProtocol(true); + case "URL" -> template.setHasURL(true); + case "DNS" -> template.setHasDNS(true); + + default -> throw new IllegalArgumentException(); + } + } + + templateMapper.newTemplate(template); + + if (template.getTemplateId() == null) { + return 0; + } + return template.getTemplateId(); + } +} diff --git a/src/main/java/com/realtime/protection/server/task/TaskController.java b/src/main/java/com/realtime/protection/server/task/TaskController.java new file mode 100644 index 0000000..e7399cc --- /dev/null +++ b/src/main/java/com/realtime/protection/server/task/TaskController.java @@ -0,0 +1,36 @@ +package com.realtime.protection.server.task; + +import com.realtime.protection.configuration.entity.task.Task; +import com.realtime.protection.configuration.response.ResponseResult; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/task") +public class TaskController { + + private final TaskService taskService; + + public TaskController(TaskService taskService) { + this.taskService = taskService; + } + + @RequestMapping("/new") + public ResponseResult newTask(@RequestBody @Valid Task task) { + Integer taskId = taskService.newTask(task); + + if (taskId > 0) { + return ResponseResult.ok() + .setData("task_name", task.getTaskName()) + .setData("task_id", taskId) + .setData("success", true); + } + + return ResponseResult.error() + .setData("task_name", task.getTaskName()) + .setData("task_id", 0) + .setData("success", false); + } +} diff --git a/src/main/java/com/realtime/protection/server/task/TaskMapper.java b/src/main/java/com/realtime/protection/server/task/TaskMapper.java new file mode 100644 index 0000000..403f2b4 --- /dev/null +++ b/src/main/java/com/realtime/protection/server/task/TaskMapper.java @@ -0,0 +1,18 @@ +package com.realtime.protection.server.task; + +import com.realtime.protection.configuration.entity.task.Task; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface TaskMapper { + void newTask(@Param("task") Task task); + + void newTaskProobjConcat(@Param("task_id") Integer taskId, @Param("proobj_ids") Integer[] proobjIds); + + Integer newTaskStaticRuleConcat(@Param("task_id") Integer taskId, + @Param("rule_ids") Integer[] staticRuleIds); + + Integer newTaskDynamicRuleConcat(@Param("task_id") Integer taskId, + @Param("rule_ids") Integer[] dynamicRuleIds); +} diff --git a/src/main/java/com/realtime/protection/server/task/TaskService.java b/src/main/java/com/realtime/protection/server/task/TaskService.java new file mode 100644 index 0000000..51905ab --- /dev/null +++ b/src/main/java/com/realtime/protection/server/task/TaskService.java @@ -0,0 +1,52 @@ +package com.realtime.protection.server.task; + +import com.realtime.protection.configuration.entity.task.Task; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@Service +public class TaskService { + + private final SqlSessionFactory sqlSessionFactory; + + public TaskService(SqlSessionFactory sqlSessionFactory) { + this.sqlSessionFactory = sqlSessionFactory; + } + + public Integer newTask(Task task) { + task.setTaskCreateTime(LocalDateTime.now()); + task.setTaskModifyTime(LocalDateTime.now()); + + SqlSession session = sqlSessionFactory.openSession(false); + TaskMapper taskMapper = session.getMapper(TaskMapper.class); + try { + taskMapper.newTask(task); + + taskMapper.newTaskProobjConcat(task.getTaskId(), task.getProtectObjectIds()); + + +// if (taskMapper.newTaskStaticRuleConcat(task.getTaskId(), task.getStaticRuleIds()) +// != task.getStaticRuleIds().length) +// throw new Exception("update lines is not equal to static_rule_ids size"); + +// if (taskMapper.newTaskDynamicRuleConcat(task.getTaskId(), task.getDynamicRuleIds()) +// != task.getDynamicRuleIds().length) +// throw new Exception("update lines is not equal to dynamic_rule_ids size"); + + session.commit(); + } catch (Exception e) { + session.rollback(); + throw e; + } finally { + session.close(); + } + + if (task.getTaskId() == null) { + return 0; + } + return task.getTaskId(); + } +} diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 19be35d..17490e7 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -7,6 +7,8 @@ spring: username: root password: aiihhbfcsy123!@# url: jdbc:mysql://localhost:3306/realtime_protection + hikari: + auto-commit: false mvc: servlet: path: /api/v1 diff --git a/src/main/resources/mappers/TaskMapper.xml b/src/main/resources/mappers/TaskMapper.xml new file mode 100644 index 0000000..c1aebeb --- /dev/null +++ b/src/main/resources/mappers/TaskMapper.xml @@ -0,0 +1,38 @@ + + + + + INSERT INTO t_task(task_name, task_start_time, task_end_time, + task_act, task_type, + task_create_time, task_modify_time, + task_create_userid, task_create_username, task_create_depart) + VALUE(#{task.taskName}, #{task.taskStartTime}, #{task.taskEndTime}, + #{task.taskAct}, #{task.taskType}, + #{task.taskCreateTime}, #{task.taskModifyTime}, + #{task.taskCreateUserId}, #{task.taskCreateUsername}, #{task.taskCreateDepart}) + + + + + INSERT INTO t_task_project_object(task_id, protect_object_id) + VALUES + + (#{task_id}, #{proobj_id}) + + + + + + UPDATE t_static_rule + SET static_rule_used_task_id = #{task_id} + WHERE static_rule_id IN + + #{rule_id} + + + + + \ No newline at end of file diff --git a/src/main/resources/mappers/TemplateMapper.xml b/src/main/resources/mappers/TemplateMapper.xml new file mode 100644 index 0000000..0c64032 --- /dev/null +++ b/src/main/resources/mappers/TemplateMapper.xml @@ -0,0 +1,22 @@ + + + + + INSERT INTO t_strategy_template(strategy_template_name, + has_protect_object_ip, has_protect_object_port, + has_peer_ip, has_peer_port, + has_protocol, has_url, has_dns, + strategy_template_create_user_id, + strategy_template_create_username, strategy_template_create_depart, + default_op) + VALUE (#{template.templateName}, + #{template.hasProtectObjectIP}, #{template.hasProtectObjectPort}, + #{template.hasPeerIP}, #{template.hasPeerPort}, + #{template.hasProtocol}, #{template.hasURL}, #{template.hasDNS}, + 0, + #{template.templateName}, #{template.templateName}, + #{template.defaultOp}) + + \ No newline at end of file diff --git a/src/test/java/com/realtime/protection/server/defense/template/TemplateServiceTest.java b/src/test/java/com/realtime/protection/server/defense/template/TemplateServiceTest.java new file mode 100644 index 0000000..16328e2 --- /dev/null +++ b/src/test/java/com/realtime/protection/server/defense/template/TemplateServiceTest.java @@ -0,0 +1,45 @@ +package com.realtime.protection.server.defense.template; + +import com.realtime.protection.configuration.entity.defense.template.Template; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class TemplateServiceTest { + + private final TemplateService templateService; + private Template template; + + @Autowired + TemplateServiceTest(TemplateService templateService) { + this.templateService = templateService; + } + + @BeforeEach + void mockTemplate() { + template = new Template(); + + template.setTemplateName("反射型DDOS攻击"); + template.setTemplateElements(new String[]{"对端IP", "协议", "URL"}); + template.setDefaultOp("阻断"); + } + + @Test + void testNewTemplateSuccess() { + Integer templateId = templateService.newTemplate(template); + assertTrue(templateId > 0); + } + + @Test + void testNewTemplateIllegalArgument() { + template.setTemplateElements(new String[]{"DDNS"}); + assertThrows(IllegalArgumentException.class, () -> { + Integer templateId = templateService.newTemplate(template); + assertTrue(templateId > 0); + }); + } +} \ No newline at end of file diff --git a/src/test/java/com/realtime/protection/server/task/TaskControllerTest.java b/src/test/java/com/realtime/protection/server/task/TaskControllerTest.java new file mode 100644 index 0000000..7d196e2 --- /dev/null +++ b/src/test/java/com/realtime/protection/server/task/TaskControllerTest.java @@ -0,0 +1,10 @@ +package com.realtime.protection.server.task; + +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class TaskControllerTest { + +} \ No newline at end of file diff --git a/src/test/java/com/realtime/protection/server/task/TaskServiceTest.java b/src/test/java/com/realtime/protection/server/task/TaskServiceTest.java new file mode 100644 index 0000000..aa0a226 --- /dev/null +++ b/src/test/java/com/realtime/protection/server/task/TaskServiceTest.java @@ -0,0 +1,57 @@ +package com.realtime.protection.server.task; + +import com.realtime.protection.configuration.entity.task.Task; +import org.apache.ibatis.exceptions.PersistenceException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class TaskServiceTest { + private final TaskService taskService; + private Task task; + + @Autowired + TaskServiceTest(TaskService taskService) { + this.taskService = taskService; + } + + @BeforeEach + public void taskInit() { + this.task = new Task(); + task.setTaskName("静态测试"); + + LocalDateTime taskStartTime = LocalDateTime.parse("2023-12-24T11:45:14"); + LocalDateTime taskEndTime = LocalDateTime.parse("2023-12-29T11:45:12"); + + task.setTaskStartTime(taskStartTime); + task.setTaskEndTime(taskEndTime); + task.setTaskAct("阻断"); + task.setTaskType("静态任务"); + task.setStaticRuleIds(new Integer[]{1}); + task.setDynamicRuleIds(new Integer[]{}); + task.setTaskCreateUserId(1); + task.setTaskCreateUsername("xxx"); + task.setTaskCreateDepart("xxx"); + task.setProtectObjectIds(new Integer[]{1}); + } + + @Test + void testNewTaskSuccess() { + assertDoesNotThrow(() -> {Integer taskId = taskService.newTask(task); assertTrue(taskId > 0);}); + } + + @Test + void testNewTaskLostData() { + this.task.setTaskStartTime(null); + assertThrows(PersistenceException.class, () -> { + Integer taskId = taskService.newTask(task); + assertTrue(taskId > 0); + }); + } +} \ No newline at end of file