From 64f5a4692833a6535e308878c6d6f9dcaaa6b8a9 Mon Sep 17 00:00:00 2001 From: shizhendong Date: Wed, 4 Sep 2024 13:46:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ASW-49=20=E6=96=B0=E5=A2=9E=20applicati?= =?UTF-8?q?on=20=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 实现 ASW-Controller,TSG application 格式互转 --- .../net/geedge/asw/common/util/RCode.java | 1 + .../app/controller/ApplicationController.java | 70 +- ...ava => IApplicationAttachmentService.java} | 2 +- ...vice.java => IApplicationNoteService.java} | 2 +- .../app/service/IApplicationService.java | 6 + ...java => IApplicationSignatureService.java} | 5 +- .../app/service/ITSGApplicationService.java | 15 + .../ApplicationAttachmentServiceImpl.java | 4 +- .../impl/ApplicationNoteServiceImpl.java | 4 +- .../service/impl/ApplicationServiceImpl.java | 51 +- .../impl/ApplicationSignatureServiceImpl.java | 24 +- .../impl/TSGApplicationServiceImpl.java | 807 ++++++++++++++++++ .../controller/AttributeController.java | 4 +- ...uteService.java => IAttributeService.java} | 4 +- .../service/impl/AttributeServiceImpl.java | 16 +- .../resources/db/migration/R__AZ_sys_i18n.sql | 2 + 16 files changed, 986 insertions(+), 31 deletions(-) rename src/main/java/net/geedge/asw/module/app/service/{ApplicationAttachmentService.java => IApplicationAttachmentService.java} (85%) rename src/main/java/net/geedge/asw/module/app/service/{ApplicationNoteService.java => IApplicationNoteService.java} (74%) rename src/main/java/net/geedge/asw/module/app/service/{ApplicationSignatureService.java => IApplicationSignatureService.java} (73%) create mode 100644 src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java create mode 100644 src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java rename src/main/java/net/geedge/asw/module/attribute/service/{AttributeService.java => IAttributeService.java} (70%) diff --git a/src/main/java/net/geedge/asw/common/util/RCode.java b/src/main/java/net/geedge/asw/common/util/RCode.java index dd36115..4af43ae 100644 --- a/src/main/java/net/geedge/asw/common/util/RCode.java +++ b/src/main/java/net/geedge/asw/common/util/RCode.java @@ -47,6 +47,7 @@ public enum RCode { APP_NOTE_CONTENT_CANNOT_EMPTY(201014, "application note content cannot be empty"), APP_ATTACHMENT_NOT_EXIST(201015, "application attachment does not exist"), APP_PROPERTIES_FORMAT_ERROR(201016, "application properties format error"), + APP_IMPORT_FILE_FORMAT_ERROR(201017, "application import file format error"), diff --git a/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java b/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java index 08a6abc..10ef8bb 100644 --- a/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java +++ b/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java @@ -1,5 +1,6 @@ package net.geedge.asw.module.app.controller; +import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.servlet.http.HttpServletResponse; @@ -11,10 +12,12 @@ import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity; import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationNoteEntity; import net.geedge.asw.module.app.entity.ApplicationSignatureEntity; -import net.geedge.asw.module.app.service.ApplicationAttachmentService; -import net.geedge.asw.module.app.service.ApplicationNoteService; -import net.geedge.asw.module.app.service.ApplicationSignatureService; +import net.geedge.asw.module.app.service.IApplicationAttachmentService; +import net.geedge.asw.module.app.service.IApplicationNoteService; import net.geedge.asw.module.app.service.IApplicationService; +import net.geedge.asw.module.app.service.IApplicationSignatureService; +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.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -22,22 +25,26 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @RestController @RequestMapping("/api/v1/application") public class ApplicationController { + @Autowired + private IWorkspaceService workspaceService; + @Autowired private IApplicationService applicationService; @Autowired - private ApplicationSignatureService signatureService; + private IApplicationSignatureService signatureService; @Autowired - private ApplicationNoteService noteService; + private IApplicationNoteService noteService; @Autowired - private ApplicationAttachmentService attachmentService; + private IApplicationAttachmentService attachmentService; @GetMapping("/{id}") public R detail(@PathVariable("id") String id, String workspaceId) { @@ -182,4 +189,55 @@ public class ApplicationController { return R.ok(); } + + @PostMapping("/import") + public R importApplication(@RequestParam String workspaceId, + @RequestParam(defaultValue = "tsg2402") String format, + @RequestParam(value = "files") List fileList) { + // validate + WorkspaceEntity workspace = workspaceService.getById(workspaceId); + T.VerifyUtil.is(workspace).notNull(RCode.WORKSPACE_NOT_EXIST); + + List dataList = T.ListUtil.list(true); + try { + for (MultipartFile multipartFile : fileList) { + String str = T.IoUtil.readUtf8(multipartFile.getInputStream()); + JSONObject jsonObject = T.JSONUtil.parseObj(str); + if (null == jsonObject.getJSONArray("applications")) { + continue; + } + dataList.add(jsonObject); + } + } catch (Exception e) { + throw new ASWException(RCode.APP_IMPORT_FILE_FORMAT_ERROR); + } + + // import + List entityList = applicationService.importAppByFormat(workspaceId, format, dataList); + List> records = entityList.stream() + .map(entity -> Map.of("id", entity.getId())) + .collect(Collectors.toList()); + return R.ok().putData("records", records); + } + + @GetMapping("/export") + public void exportApplication(@RequestParam String workspaceId, + @RequestParam String ids, + @RequestParam(defaultValue = "tsg2402") String format, + HttpServletResponse response) throws IOException { + // validate + List appList = applicationService.list( + new LambdaQueryWrapper() + .eq(ApplicationEntity::getWorkspaceId, workspaceId) + .in(ApplicationEntity::getId, T.ListUtil.of(ids.split(","))) + ); + T.VerifyUtil.is(appList).notEmpty(RCode.APP_NOT_EXIST); + + // format + byte[] bytes = applicationService.exportAppByFormat(appList, format); + + // response + T.ResponseUtil.downloadFile(response, T.StrUtil.concat(true, "application_", System.currentTimeMillis() + ".json"), bytes); + } + } diff --git a/src/main/java/net/geedge/asw/module/app/service/ApplicationAttachmentService.java b/src/main/java/net/geedge/asw/module/app/service/IApplicationAttachmentService.java similarity index 85% rename from src/main/java/net/geedge/asw/module/app/service/ApplicationAttachmentService.java rename to src/main/java/net/geedge/asw/module/app/service/IApplicationAttachmentService.java index 9b8cdc6..c6f827b 100644 --- a/src/main/java/net/geedge/asw/module/app/service/ApplicationAttachmentService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IApplicationAttachmentService.java @@ -7,7 +7,7 @@ import org.springframework.core.io.Resource; import java.io.IOException; -public interface ApplicationAttachmentService extends IService{ +public interface IApplicationAttachmentService extends IService{ ApplicationAttachmentEntity saveAttachment(Resource fileResource, String applicationId); diff --git a/src/main/java/net/geedge/asw/module/app/service/ApplicationNoteService.java b/src/main/java/net/geedge/asw/module/app/service/IApplicationNoteService.java similarity index 74% rename from src/main/java/net/geedge/asw/module/app/service/ApplicationNoteService.java rename to src/main/java/net/geedge/asw/module/app/service/IApplicationNoteService.java index cf75795..0464bd6 100644 --- a/src/main/java/net/geedge/asw/module/app/service/ApplicationNoteService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IApplicationNoteService.java @@ -3,7 +3,7 @@ package net.geedge.asw.module.app.service; import com.baomidou.mybatisplus.extension.service.IService; import net.geedge.asw.module.app.entity.ApplicationNoteEntity; -public interface ApplicationNoteService extends IService{ +public interface IApplicationNoteService extends IService{ void saveNote(ApplicationNoteEntity note, String applicationId); } diff --git a/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java b/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java index b455401..aa4a5ef 100644 --- a/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java @@ -1,5 +1,6 @@ package net.geedge.asw.module.app.service; +import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import net.geedge.asw.module.app.entity.ApplicationEntity; @@ -20,4 +21,9 @@ public interface IApplicationService extends IService{ ApplicationEntity updateBasic(ApplicationEntity entity); void removeApplication(List ids); + + byte[] exportAppByFormat(List appList, String format); + + List importAppByFormat(String workspaceId, String format, List dataList); + } diff --git a/src/main/java/net/geedge/asw/module/app/service/ApplicationSignatureService.java b/src/main/java/net/geedge/asw/module/app/service/IApplicationSignatureService.java similarity index 73% rename from src/main/java/net/geedge/asw/module/app/service/ApplicationSignatureService.java rename to src/main/java/net/geedge/asw/module/app/service/IApplicationSignatureService.java index d8b3528..d426d8d 100644 --- a/src/main/java/net/geedge/asw/module/app/service/ApplicationSignatureService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IApplicationSignatureService.java @@ -5,7 +5,7 @@ import net.geedge.asw.module.app.entity.ApplicationSignatureEntity; import java.util.List; -public interface ApplicationSignatureService extends IService{ +public interface IApplicationSignatureService extends IService{ void saveSignature(ApplicationSignatureEntity signature, String applicationId); @@ -14,4 +14,7 @@ public interface ApplicationSignatureService extends IService compare(String applicationId, String oldVersion, String newVersion); void restore(String id, String version); + + ApplicationSignatureEntity queryLastVersionSignatureByAppId(String applicationId); + } diff --git a/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java b/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java new file mode 100644 index 0000000..eda42bc --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java @@ -0,0 +1,15 @@ +package net.geedge.asw.module.app.service; + +import cn.hutool.json.JSONObject; +import net.geedge.asw.module.app.entity.ApplicationEntity; + +import java.util.List; +import java.util.Map; + +public interface ITSGApplicationService { + + Map aswToTsg2402(List appList); + + List tsg2402ToAsw(String workspaceId, List dataList); + +} \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java index eee59fe..eda3339 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java @@ -12,7 +12,7 @@ import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.dao.ApplicationAttachmentDao; import net.geedge.asw.module.app.entity.ApplicationAttachmentEntity; import net.geedge.asw.module.app.entity.ApplicationEntity; -import net.geedge.asw.module.app.service.ApplicationAttachmentService; +import net.geedge.asw.module.app.service.IApplicationAttachmentService; import net.geedge.asw.module.app.service.IApplicationService; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -26,7 +26,7 @@ import java.util.Arrays; import java.util.List; @Service -public class ApplicationAttachmentServiceImpl extends ServiceImpl implements ApplicationAttachmentService { +public class ApplicationAttachmentServiceImpl extends ServiceImpl implements IApplicationAttachmentService { private static final Log log = Log.get(); diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationNoteServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationNoteServiceImpl.java index 690915c..2a346e8 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationNoteServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationNoteServiceImpl.java @@ -6,12 +6,12 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.dao.ApplicationNoteDao; import net.geedge.asw.module.app.entity.ApplicationNoteEntity; -import net.geedge.asw.module.app.service.ApplicationNoteService; +import net.geedge.asw.module.app.service.IApplicationNoteService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class ApplicationNoteServiceImpl extends ServiceImpl implements ApplicationNoteService { +public class ApplicationNoteServiceImpl extends ServiceImpl implements IApplicationNoteService { @Override @Transactional(rollbackFor = Exception.class) diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java index 5c8e3a9..6ed60a6 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java @@ -1,6 +1,9 @@ package net.geedge.asw.module.app.service.impl; import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.json.JSON; +import cn.hutool.json.JSONConfig; +import cn.hutool.json.JSONObject; import cn.hutool.log.Log; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -17,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -33,14 +37,16 @@ public class ApplicationServiceImpl extends ServiceImpl appList, String format) { + try { + switch (format) { + case "tsg2402": { + Map m = tsgApplicationService.aswToTsg2402(appList); + JSON json = new JSONObject(m, JSONConfig.create().setIgnoreNullValue(false).setKeyComparator(String::compareToIgnoreCase)); + return T.StrUtil.bytes(json.toJSONString(0)); + } + default: + break; + } + return new byte[]{}; + } catch (Exception e) { + log.error(e, "[exportAppByFormat] [error] [format: {}] [application: {}]", format, T.JSONUtil.toJsonStr(appList)); + throw new ASWException(RCode.ERROR); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List importAppByFormat(String workspaceId, String format, List dataList) { + try { + switch (format) { + case "tsg2402": { + List records = tsgApplicationService.tsg2402ToAsw(workspaceId, dataList); + return records; + } + default: + break; + } + return new ArrayList<>(); + } catch (Exception e) { + log.error(e, "[importAppByFormat] [error] [workspaceId: {}] [format: {}]", workspaceId, format); + throw new ASWException(RCode.ERROR); + } + } + } diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationSignatureServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationSignatureServiceImpl.java index e1c6e12..c117dc1 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationSignatureServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationSignatureServiceImpl.java @@ -8,7 +8,7 @@ import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.dao.ApplicationSignatureDao; import net.geedge.asw.module.app.entity.ApplicationSignatureEntity; -import net.geedge.asw.module.app.service.ApplicationSignatureService; +import net.geedge.asw.module.app.service.IApplicationSignatureService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,17 +17,14 @@ import java.util.List; import java.util.Map; @Service -public class ApplicationSignatureServiceImpl extends ServiceImpl implements ApplicationSignatureService { +public class ApplicationSignatureServiceImpl extends ServiceImpl implements IApplicationSignatureService { @Override @Transactional(rollbackFor = Exception.class) public void saveSignature(ApplicationSignatureEntity signature, String applicationId) { // query last note - ApplicationSignatureEntity signatureLast = this.getOne(new LambdaQueryWrapper() - .eq(ApplicationSignatureEntity::getApplicationId, applicationId) - .orderByDesc(ApplicationSignatureEntity::getOpVersion) - .last("limit 1")); + ApplicationSignatureEntity signatureLast = this.queryLastVersionSignatureByAppId(applicationId); if (T.ObjectUtil.isNotEmpty(signatureLast)){ signature.setOpVersion(signatureLast.getOpVersion() + 1); @@ -65,10 +62,7 @@ public class ApplicationSignatureServiceImpl extends ServiceImpl() .eq(ApplicationSignatureEntity::getApplicationId, applicationId) .eq(ApplicationSignatureEntity::getOpVersion, version)); - ApplicationSignatureEntity lastSignature = this.getOne(new LambdaQueryWrapper() - .eq(ApplicationSignatureEntity::getApplicationId, applicationId) - .orderByDesc(ApplicationSignatureEntity::getOpVersion) - .last("limit 1")); + ApplicationSignatureEntity lastSignature = this.queryLastVersionSignatureByAppId(applicationId); if (T.ObjectUtil.isEmpty(signature)) { throw ASWException.builder().rcode(RCode.APP_SIGNATURE_NOT_EXIST).build(); } @@ -78,4 +72,14 @@ public class ApplicationSignatureServiceImpl extends ServiceImpl() + .eq(ApplicationSignatureEntity::getApplicationId, applicationId) + .orderByDesc(ApplicationSignatureEntity::getOpVersion) + .last("limit 1")); + return entity; + } + } diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java new file mode 100644 index 0000000..7e89c9c --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java @@ -0,0 +1,807 @@ +package net.geedge.asw.module.app.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.lang.Validator; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.geedge.asw.common.util.T; +import net.geedge.asw.module.app.entity.ApplicationEntity; +import net.geedge.asw.module.app.entity.ApplicationSignatureEntity; +import net.geedge.asw.module.app.service.IApplicationService; +import net.geedge.asw.module.app.service.IApplicationSignatureService; +import net.geedge.asw.module.app.service.ITSGApplicationService; +import net.geedge.asw.module.attribute.entity.AttributeEntity; +import net.geedge.asw.module.attribute.service.IAttributeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class TSGApplicationServiceImpl implements ITSGApplicationService { + + private static final Log log = Log.get(); + + @Autowired + private IAttributeService attributeService; + + @Autowired + private IApplicationService applicationService; + + @Autowired + private IApplicationSignatureService applicationSignatureService; + + @Override + public Map aswToTsg2402(List appList) { + + List applications = this.buildTSG2402Applications(appList); + + Map signatures = this.buildTSG2402Signatures(appList); + + Map m = T.MapUtil.builder() + .put("applications", applications) + .putAll(signatures) + .build(); + return m; + } + + private List buildTSG2402Applications(List appList) { + List applications = T.ListUtil.list(true); + for (ApplicationEntity app : appList) { + // application + Map application = T.MapUtil.builder() + .put("app_name", app.getName()) + .put("app_longname", app.getName()) + .put("description", app.getDescription()) + .build(); + + // app_properties + Map properties = (Map) app.getProperties(); + Map app_properties = T.MapUtil.builder() + .put("parent_app_id", 0) + .put("parent_app_name", "null") + .put("category", T.MapUtil.getStr(properties, "category", "")) + .put("subcategory", T.MapUtil.getStr(properties, "subcategory", "")) + .put("content", T.MapUtil.getStr(properties, "content", "")) + .put("risk", T.MapUtil.getStr(properties, "risk", "1")) + .put("characteristics", T.MapUtil.getStr(properties, "characteristics", "")) + .put("deny_action", T.MapUtil.builder() + .put("method", "drop") + .put("after_n_packets", 0) + .put("send_icmp_unreachable", 0) + .put("send_tcp_reset", 0) + .build() + ) + .put("continue_scanning", 0) + .put("tcp_timeout", 0) + .put("udp_timeout", 0) + .put("tcp_half_close", 0) + .put("tcp_time_wait", 0) + .build(); + application.put("app_properties", app_properties); + + // app_surrogates + ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId()); + JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent()); + JSONArray surrogates = jsonObject.getJSONArray("surrogates"); + if (!surrogates.isEmpty()) { + List app_surrogates = T.ListUtil.list(true); + surrogates.forEach(obj -> { + List signature_sequence = T.ListUtil.list(true); + + JSONArray signatureArr = ((JSONObject) obj).getJSONArray("signatures"); + signatureArr.stream().map(o -> ((JSONObject) o).getStr("name")).forEach(tname -> { + signature_sequence.add(T.MapUtil.builder() + .put("signature", tname) + .put("exclude", 0) + .build() + ); + }); + + app_surrogates.add( + T.MapUtil.builder() + .put("group_by", "session") + .put("time_window", 0) + .put("ordered_match", "no") + .put("signature_sequence", signature_sequence) + .build() + ); + }); + application.put("app_surrogates", app_surrogates); + } + applications.add(application); + } + return applications; + } + + private Map buildTSG2402Signatures(List appList) { + List signatures = T.ListUtil.list(true); + List sig_objects = T.ListUtil.list(true); + + int sig_object_id = 10, signature_id = 0; + for (ApplicationEntity app : appList) { + ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId()); + JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent()); + JSONArray surrogates = jsonObject.getJSONArray("surrogates"); + List signaturesForApp = surrogates.stream() + .map(obj -> ((JSONObject) obj).getJSONArray("signatures")) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + for (Object object : signaturesForApp) { + JSONObject surrogate = (JSONObject) object; + + Map m = T.MapUtil.builder() + .put("signature_id", signature_id++) + .put("signature_name", T.MapUtil.getStr(surrogate, "name")) + .put("signature_desc", T.MapUtil.getStr(surrogate, "description", "")) + .put("icon_color", "") + .build(); + + List and_conditions = T.ListUtil.list(true); + JSONArray conditions = surrogate.getJSONArray("conditions"); + for (Object condition : conditions) { + JSONObject conditionJSONObj = (JSONObject) condition; + + String attributeType = T.MapUtil.getStr(conditionJSONObj, "attributeType"); + String attributeName = T.MapUtil.getStr(conditionJSONObj, "attributeName"); + AttributeEntity attributeEntity = attributeService.queryAttribute(attributeType, attributeName); + if (null == attributeEntity || T.StrUtil.isEmpty(attributeEntity.getObjectType())) continue; + + Map or_condition_obj = T.MapUtil.builder() + .put("lua_profile_id", 0) + .put("attribute_type", attributeType) + .put("attribute_name", attributeName) + .put("protocol", attributeEntity.getProtocol()) + .build(); + + List source_object_ids = T.ListUtil.list(true); + // sig_objects + JSONArray items = conditionJSONObj.getJSONArray("items"); + for (Object item : items) { + String name = T.MapUtil.getStr((JSONObject) item, "item"); + + String objectType = attributeEntity.getObjectType(); + if ("application" .equalsIgnoreCase(objectType)) continue; + + if ("boolean" .equals(objectType)) { + String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); + if ("True" .equalsIgnoreCase(itemValue)) { + source_object_ids.add(2); + } else if ("False" .equalsIgnoreCase(itemValue)) { + source_object_ids.add(3); + } else { + continue; + } + } else if ("ip_protocol" .equals(objectType)) { + String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); + if ("ICMP" .equalsIgnoreCase(itemValue)) { + source_object_ids.add(5); + } else if ("TCP" .equalsIgnoreCase(itemValue)) { + source_object_ids.add(6); + } else if ("UDP" .equalsIgnoreCase(itemValue)) { + source_object_ids.add(7); + } else { + continue; + } + } else { + source_object_ids.add(sig_object_id); + + Map member = this.buildTSG2402SignaturesMember(attributeEntity, (JSONObject) item); + + Map sig_object = T.MapUtil.builder() + .put("id", sig_object_id) + .put("source_id", sig_object_id) + .put("name", name) + .put("source_name", name) + .put("type", objectType) + .put("sub_type", attributeEntity.getType()) + .put("member_type", "item") + .put("member", member) + .put("uuid", T.IdUtil.fastSimpleUUID()) + .put("statistics_option", "none") + .build(); + sig_objects.add(sig_object); + } + sig_object_id++; + } + + or_condition_obj.put("source_object_ids", source_object_ids); + Map and_condition_item = T.MapUtil.builder() + .put("not_flag", T.MapUtil.getBool(conditionJSONObj, "negate_option", false) ? 1 : 0) + .put("or_conditions", T.ListUtil.of(or_condition_obj)) + .build(); + and_conditions.add(and_condition_item); + } + + m.put("and_conditions", and_conditions); + signatures.add(m); + } + } + sig_objects.add(T.JSONUtil.parseObj(""" + { + "id": 2, + "type": "boolean", + "name": "True", + "vsys_id": 0, + "description": "True", + "source_id": 2, + "source_name": "True", + "member_type": "item", + "uuid": "c4ca4238a0b923820dcc509a6f75849b", + "statistics_option": "elaborate" + } + """)); + sig_objects.add(T.JSONUtil.parseObj(""" + { + "id": 3, + "type": "boolean", + "name": "False", + "vsys_id": 0, + "description": "False", + "source_id": 3, + "source_name": "False", + "member_type": "item", + "uuid": "cfcd208495d565ef66e7dff9f98764da", + "statistics_option": "elaborate" + } + """)); + sig_objects.add(T.JSONUtil.parseObj(""" + { + "id": 5, + "type": "ip_protocol", + "name": "ICMP", + "vsys_id": 0, + "description": "ICMP", + "source_id": 5, + "source_name": "ICMP", + "member_type": "item", + "uuid": "c4ca4238a0b923820dcc509a6f75849b", + "statistics_option": "elaborate" + } + """)); + sig_objects.add(T.JSONUtil.parseObj(""" + { + "id": 6, + "type": "ip_protocol", + "name": "TCP", + "vsys_id": 0, + "description": "TCP", + "source_id": 6, + "source_name": "TCP", + "member_type": "item", + "uuid": "1679091c5a880faf6fb5e6087eb1b2dc", + "statistics_option": "elaborate" + } + """)); + sig_objects.add(T.JSONUtil.parseObj(""" + { + "id": 7, + "type": "ip_protocol", + "name": "UDP", + "vsys_id": 0, + "description": "UDP", + "source_id": 7, + "source_name": "UDP", + "member_type": "item", + "uuid": "70efdf2ec9b086079795c442636b55fb", + "statistics_option": "elaborate" + } + """)); + Map m = T.MapUtil.builder() + .put("signatures", signatures) + .put("sig_objects", sig_objects) + .build(); + return m; + } + + private Map buildTSG2402SignaturesMember(AttributeEntity attributeEntity, JSONObject item) { + List list = T.ListUtil.list(true); + String objectType = attributeEntity.getObjectType().toLowerCase(); + switch (objectType) { + case "keywords": + case "http_signature": { + String str = item.getStr("item"); + List patternExprList = T.ListUtil.list(true); + patternExprList.add(str); + + // 0 -> 无表达式,1 -> 与表达式,2 -> 正则表达式,3、带偏移量的子串匹配 + int expr_type = 0; + String exprType = item.getStr("exprType", "and"); + if ("and" .equalsIgnoreCase(exprType)) { + patternExprList = T.StrUtil.split(str, "&"); + if (patternExprList.size() > 1) { + expr_type = 1; + } + } else if ("regex" .equalsIgnoreCase(exprType)) { + expr_type = 2; + } + + JSONArray patternArr = new JSONArray(); + for (String expr : patternExprList) { + JSONObject pattern = new JSONObject(); + pattern.put("keywords", expr); + + Map rangeVarMap = this.getRangeVarFromExpr(expr); + if (T.MapUtil.isNotEmpty(rangeVarMap)) { + expr_type = 3; + pattern.put("keywords", expr.replaceAll("^\\(.*?\\)", "")); + pattern.put("offset", T.MapUtil.getInt(rangeVarMap, "offset")); + pattern.put("depth", T.MapUtil.getInt(rangeVarMap, "depth")); + } + patternArr.add(pattern); + } + + if ("keywords" .equals(objectType)) { + Map m = T.MapUtil.builder() + .put("string", T.MapUtil.builder() + .put("item_type", "keywords") + .put("expr_type", expr_type) + .put("is_hexbin", 0) + .put("patterns", patternArr) + .build() + ).build(); + list.add(m); + } + if("http_signature".equals(objectType)){ + Map m = T.MapUtil.builder() + .put("contextual_string", T.MapUtil.builder() + .put("expr_type", expr_type) + .put("is_hexbin", 0) + .put("context_name", item.getStr("district", "Set-Cookie")) + .put("patterns", patternArr) + .build() + ) + .build(); + list.add(m); + } + break; + } + case "url": + case "fqdn": { + Map m = T.MapUtil.builder() + .put("string", T.MapUtil.builder() + .put("item_type", objectType) + .put("expr_type", 0) + .put("is_hexbin", 0) + .put("patterns", T.ListUtil.of( + new JSONObject().put("keywords", item.getStr("item")) + )) + .build() + ) + .build(); + list.add(m); + break; + } + case "ip": { + String str = item.getStr("item"); + String ip = str; + String port = "0-65535"; + if (str.contains("#")) { + ip = str.split("#")[0]; + port = str.split("#")[1]; + } + Map m = T.MapUtil.builder() + .put("ip", T.MapUtil.builder() + .put("addr_type", Validator.isIpv4(str) ? 4 : 6) + .put("port", port) + .put("ip_address", ip) + .build() + ) + .build(); + list.add(m); + break; + } + case "port": { + String port = item.getStr("item"); + Map m = T.MapUtil.builder() + .put("port", new JSONObject().put("port", port)) + .build(); + if (port.contains("-")) { + m.put("port", new JSONObject().put("port_range", port)); + } + list.add(m); + break; + } + case "interval": { + String str = item.getStr("item"); + String low_boundary = str, up_boundary = str; + if (str.contains("-")) { + low_boundary = item.getStr("item").split("-")[0]; + up_boundary = item.getStr("item").split("-")[1]; + } + Map m = T.MapUtil.builder() + .put("interval", T.MapUtil.builder() + .put("low_boundary", low_boundary) + .put("up_boundary", up_boundary) + .build() + ) + .build(); + list.add(m); + break; + } + case "boolean": + case "ip_protocol": + case "application": { + break; + } + default: + break; + } + + Map member = T.MapUtil.builder() + .put("items", list) + .build(); + return member; + } + + /** + * 获取表达式中的 range 变量,示例 (nocase=off,offset=6,depth=13)expr_xxxxxxxxx + */ + private Map getRangeVarFromExpr(String expr) { + try { + String regex = "^\\(([^)]+)\\)"; + String str = T.ReUtil.get(regex, expr, 1); + if (T.StrUtil.isNotEmpty(str)) { + String[] pairs = str.split(","); + + Map map = new HashMap<>(); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + map.put(keyValue[0].trim(), keyValue[1].trim()); + } + } + // 不包含 offset,depth 算没有配置 + if (!map.containsKey("offset") || !map.containsKey("depth")) { + return new HashMap<>(); + } + return map; + } + } catch (Exception e) { + log.error(e, "[getRangeVarFromExpr] [expr: {}]", expr); + } + return new HashMap<>(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List tsg2402ToAsw(String workspaceId, List dataList) { + List records = T.ListUtil.list(true); + for (JSONObject tsgAppSourceData : dataList) { + + JSONArray all_application = tsgAppSourceData.getJSONArray("applications"); + JSONArray all_signature = tsgAppSourceData.getJSONArray("signatures"); + JSONArray all_sig_object = tsgAppSourceData.getJSONArray("sig_objects"); + + all_application.stream() + .map(obj -> (JSONObject) obj) + .forEach(application -> { + // application + String app_name = application.getStr("app_name"); + String description = application.getStr("description"); + + JSONObject appProperties = application.getJSONObject("app_properties"); + String category = T.MapUtil.getStr(appProperties, "category", ""); + String subcategory = T.MapUtil.getStr(appProperties, "subcategory", ""); + String content = T.MapUtil.getStr(appProperties, "content", ""); + int risk = T.MapUtil.getInt(appProperties, "risk", 1); + String characteristics = T.MapUtil.getStr(appProperties, "characteristics", ""); + + Map properties = T.MapUtil.builder() + .put("category", category) + .put("subcategory", subcategory) + .put("content", content) + .put("risk", risk) + .put("characteristics", characteristics) + .build(); + + // save or update application + ApplicationEntity entity = new ApplicationEntity(); + entity.setName(app_name); + entity.setDescription(description); + entity.setProperties(properties); + entity.setPackageName("{}"); + entity.setWorkspaceId(workspaceId); + entity.setCreateTimestamp(System.currentTimeMillis()); + entity.setUpdateTimestamp(System.currentTimeMillis()); + entity.setCreateUserId(StpUtil.getLoginIdAsString()); + entity.setUpdateUserId(StpUtil.getLoginIdAsString()); + + ApplicationEntity one = applicationService.getOne(new LambdaQueryWrapper() + .eq(ApplicationEntity::getWorkspaceId, workspaceId) + .eq(ApplicationEntity::getName, app_name)); + if (null != one) { + entity.setId(one.getId()); + } + applicationService.saveOrUpdate(entity); + + records.add(entity); + String applicationId = entity.getId(); + + // surrogate - signature + Map> surrAndSignListMap = T.MapUtil.newHashMap(); + JSONArray app_surrogates = application.getJSONArray("app_surrogates"); + if (T.ObjectUtil.isNotEmpty(app_surrogates)) { + for (int i = 0; i < app_surrogates.size(); i++) { + JSONObject surrogate = (JSONObject) app_surrogates.get(i); + List signatureNameList = (List) T.JSONUtil.getByPath(surrogate, "signature_sequence.signature"); + surrAndSignListMap.put("surrogate_" + (i + 1), signatureNameList); + } + } + + + List insertSurrogateList = T.ListUtil.list(true); + for (Map.Entry> entry : surrAndSignListMap.entrySet()) { + String surrogateName = entry.getKey(); + + List signatureNameList = entry.getValue(); + List signatureListInApp = all_signature.stream() + .filter(obj -> { + String str = T.MapUtil.getStr((JSONObject) obj, "signature_name", ""); + return signatureNameList.contains(str); + }) + .map(obj -> (JSONObject) obj) + .collect(Collectors.toList()); + if (T.CollUtil.isEmpty(signatureListInApp)) continue; + + List sigObjectList = all_sig_object.stream() + .map(obj -> (JSONObject) obj) + .collect(Collectors.toList()); + Map aswSrrogate = this.buildAswSurrogateFromTSG2402(surrogateName, signatureListInApp, sigObjectList); + insertSurrogateList.add(aswSrrogate); + } + + Map sm = T.MapUtil.builder() + .put("surrogates", insertSurrogateList) + .build(); + + // save application signatrue + ApplicationSignatureEntity signatureEntity = new ApplicationSignatureEntity(); + signatureEntity.setApplicationId(applicationId); + signatureEntity.setContent(T.JSONUtil.toJsonStr(sm)); + signatureEntity.setCreateTimestamp(System.currentTimeMillis()); + signatureEntity.setCreateUserId(StpUtil.getLoginIdAsString()); + signatureEntity.setOpVersion(0L); + + ApplicationSignatureEntity signatureLast = applicationSignatureService.queryLastVersionSignatureByAppId(applicationId); + if (T.ObjectUtil.isNotEmpty(signatureLast)) { + signatureEntity.setOpVersion(signatureLast.getOpVersion() + 1); + } + applicationSignatureService.save(signatureEntity); + }); + } + return records; + } + + private Map buildAswSurrogateFromTSG2402(String surrogateName, List signatureList, List sigObjectList) { + // surrogate + Map surrogate = T.MapUtil.builder() + .put("name", surrogateName) + .put("description", "") + .build(); + + // signatures + List signatures = T.ListUtil.list(true); + for (JSONObject jsonObject : signatureList) { + String signature_name = jsonObject.getStr("signature_name"); + String signature_description = jsonObject.getStr("signature_desc"); + + Map signMap = T.MapUtil.builder() + .put("name", signature_name) + .put("description", signature_description) + .build(); + + // conditions + List> conditionMapList = T.ListUtil.list(true); + + JSONArray and_conditions = jsonObject.getJSONArray("and_conditions"); + for (Object obj : and_conditions) { + JSONObject conditions = (JSONObject) obj; + // base field + Integer not_flag = conditions.getInt("not_flag", 0); + + JSONObject or_condition = (JSONObject) T.JSONUtil.getByPath(conditions, "or_conditions[0]"); + String attribute_name = or_condition.getStr("attribute_name", ""); + String attribute_type = or_condition.getStr("attribute_type", ""); + + Map m = T.MapUtil.builder() + .put("attributeName", attribute_name) + .put("attributeType", attribute_type) + .put("negate_option", not_flag == 1 ? true : false) + .put("description", "") + .build(); + + // items + List source_object_ids = (List) T.JSONUtil.getByPath(or_condition, "source_object_ids"); + if (T.CollUtil.isEmpty(source_object_ids)) continue; + + List sourceObjectList = sigObjectList.stream() + .filter(entries -> { + Integer anInt = entries.getInt("id"); + return source_object_ids.contains(anInt); + }) + .collect(Collectors.toList()); + + List> itemList = this.buildAswConditionItemsFromTSG2402(sourceObjectList); + if (T.CollUtil.isEmpty(itemList)) continue; + + // 按 item value 去重 + List> distinctItemList = itemList.stream() + .collect(Collectors.collectingAndThen( + Collectors.toMap( + map -> map.get("item"), + map -> map, + (existing, replacement) -> existing // 保留第一个出现的元素 + ), + map -> new ArrayList(map.values()) + )); + m.put("items", distinctItemList); + conditionMapList.add(m); + } + + signMap.put("conditions", conditionMapList); + signatures.add(signMap); + } + + surrogate.put("signatures", signatures); + return surrogate; + } + + private List> buildAswConditionItemsFromTSG2402(List sourceObjectList) { + List> iiemList = T.ListUtil.list(true); + for (JSONObject jsonObject : sourceObjectList) { + + String type = jsonObject.getStr("type"); + JSONArray itemArr = (JSONArray) T.JSONUtil.getByPath(jsonObject, "member.items"); + itemArr = T.CollUtil.defaultIfEmpty(itemArr, new JSONArray()); + + switch (type) { + case "http_signature": + case "keywords": { + String exprTypeJsonPath = "keywords" .equals(type) ? "string.expr_type" : "contextual_string.expr_type"; + String firstExprJsonPath = "keywords" .equals(type) ? "string.patterns[0].keywords" : "contextual_string.patterns[0].keywords"; + String patternsJsonPath = "keywords" .equals(type) ? "string.patterns" : "contextual_string.patterns"; + + itemArr.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + // 0 -> 无表达式,1 -> 与表达式,2 -> 正则表达式,3、带偏移量的子串匹配 + Integer expr_type = (Integer) T.JSONUtil.getByPath(item, exprTypeJsonPath); + + String tempType = "and"; + String expr = (String) T.JSONUtil.getByPath(item, firstExprJsonPath); + switch (expr_type) { + case 0: + break; + case 1: { + JSONArray patterns = (JSONArray) T.JSONUtil.getByPath(item, patternsJsonPath); + expr = patterns.stream() + .map(obj -> ((JSONObject) obj).getStr("keywords")) + .collect(Collectors.joining("&")); + break; + } + case 2: + tempType = "regex"; + break; + case 3: { + JSONArray patterns = (JSONArray) T.JSONUtil.getByPath(item, patternsJsonPath); + expr = patterns.stream() + .map(obj -> { + String keywords = ((JSONObject) obj).getStr("keywords"); + String offset = ((JSONObject) obj).getStr("offset"); + String depth = ((JSONObject) obj).getStr("depth"); + return T.StrUtil.concat(true, "(offset=", offset, ",depth=", depth, ")", keywords); + }) + .collect(Collectors.joining("&")); + break; + } + default: + break; + } + Map m = T.MapUtil.builder() + .put("item", expr) + .put("exprType", tempType) + .put("description", "") + .build(); + String context_name = (String) T.JSONUtil.getByPath(item, "contextual_string.context_name"); + if (T.StrUtil.isNotEmpty(context_name)) { + m.put("district", context_name); + } + iiemList.add(m); + }); + break; + } + case "url": + case "fqdn": { + itemArr.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + String str = (String) T.JSONUtil.getByPath(item, "string.patterns[0].keywords"); + iiemList.add( + T.MapUtil.builder() + .put("item", str) + .put("description", "") + .build() + ); + }); + break; + } + case "ip": { + itemArr.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + String port = (String) T.JSONUtil.getByPath(item, "ip.port"); + String ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_address"); + if (T.StrUtil.isEmpty(ipAddress)) { + ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_cidr"); + } + if (T.StrUtil.isEmpty(ipAddress)) { + ipAddress = (String) T.JSONUtil.getByPath(item, "ip.ip_range"); + } + if (!"0-65535" .equalsIgnoreCase(port)) { + ipAddress = T.StrUtil.concat(true, ipAddress, "#", port); + } + iiemList.add( + T.MapUtil.builder() + .put("item", ipAddress) + .put("description", "") + .build() + ); + }); + break; + } + case "port": { + itemArr.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + String port = (String) T.JSONUtil.getByPath(item, "port.port"); + if (T.StrUtil.isEmpty(port)) { + port = (String) T.JSONUtil.getByPath(item, "port.port_range"); + } + iiemList.add( + T.MapUtil.builder() + .put("item", port) + .put("description", "") + .build() + ); + }); + break; + } + case "interval": { + itemArr.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + Object low_boundary = T.JSONUtil.getByPath(item, "interval.low_boundary"); + Object up_boundary = T.JSONUtil.getByPath(item, "interval.up_boundary"); + Map m = T.MapUtil.builder() + .put("item", low_boundary + "-" + up_boundary) + .put("description", "") + .build(); + iiemList.add(m); + }); + break; + } + case "boolean": + case "ip_protocol": { + Map m = T.MapUtil.builder() + .put("item", jsonObject.getStr("name")) + .put("description", "") + .build(); + iiemList.add(m); + break; + } + case "application": { + break; + } + default: + break; + } + } + return iiemList; + } + +} \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/attribute/controller/AttributeController.java b/src/main/java/net/geedge/asw/module/attribute/controller/AttributeController.java index f2872fd..4ad5e7f 100644 --- a/src/main/java/net/geedge/asw/module/attribute/controller/AttributeController.java +++ b/src/main/java/net/geedge/asw/module/attribute/controller/AttributeController.java @@ -2,7 +2,7 @@ package net.geedge.asw.module.attribute.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import net.geedge.asw.common.util.R; -import net.geedge.asw.module.attribute.service.AttributeService; +import net.geedge.asw.module.attribute.service.IAttributeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -16,7 +16,7 @@ import java.util.Map; public class AttributeController { @Autowired - private AttributeService attributeService; + private IAttributeService attributeService; @GetMapping public R list(@RequestParam Map params) { diff --git a/src/main/java/net/geedge/asw/module/attribute/service/AttributeService.java b/src/main/java/net/geedge/asw/module/attribute/service/IAttributeService.java similarity index 70% rename from src/main/java/net/geedge/asw/module/attribute/service/AttributeService.java rename to src/main/java/net/geedge/asw/module/attribute/service/IAttributeService.java index 31e04c7..7716ab1 100644 --- a/src/main/java/net/geedge/asw/module/attribute/service/AttributeService.java +++ b/src/main/java/net/geedge/asw/module/attribute/service/IAttributeService.java @@ -6,6 +6,8 @@ import net.geedge.asw.module.attribute.entity.AttributeEntity; import java.util.Map; -public interface AttributeService extends IService { +public interface IAttributeService extends IService { Page queryList(Map params); + + AttributeEntity queryAttribute(String type, String name); } diff --git a/src/main/java/net/geedge/asw/module/attribute/service/impl/AttributeServiceImpl.java b/src/main/java/net/geedge/asw/module/attribute/service/impl/AttributeServiceImpl.java index 4367542..6dd5cad 100644 --- a/src/main/java/net/geedge/asw/module/attribute/service/impl/AttributeServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/attribute/service/impl/AttributeServiceImpl.java @@ -1,19 +1,20 @@ package net.geedge.asw.module.attribute.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import net.geedge.asw.common.util.T; import net.geedge.asw.module.attribute.dao.AttributeDao; import net.geedge.asw.module.attribute.entity.AttributeEntity; -import net.geedge.asw.module.attribute.service.AttributeService; +import net.geedge.asw.module.attribute.service.IAttributeService; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service -public class AttributeServiceImpl extends ServiceImpl implements AttributeService { +public class AttributeServiceImpl extends ServiceImpl implements IAttributeService { @Override @@ -24,4 +25,15 @@ public class AttributeServiceImpl extends ServiceImpl() + .eq(AttributeEntity::getType, type) + .eq(AttributeEntity::getName, name) + .last("limit 1") + ); + return one; + } + } diff --git a/src/main/resources/db/migration/R__AZ_sys_i18n.sql b/src/main/resources/db/migration/R__AZ_sys_i18n.sql index 8c93e58..95ce275 100644 --- a/src/main/resources/db/migration/R__AZ_sys_i18n.sql +++ b/src/main/resources/db/migration/R__AZ_sys_i18n.sql @@ -125,5 +125,7 @@ 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 (207, '601001', 'ENVIRONMENT_SESSION_NOT_EXIST', '会话不存在', 'zh', '', 'admin', 1724030366000); INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (209, '601002', 'ENVIRONMENT_NOT_EXIST', 'environment does not exist', 'en', '', 'admin', 1724030366000); INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (211, '601002', 'ENVIRONMENT_NOT_EXIST', '环境不存在', 'zh', '', 'admin', 1724030366000); +INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (213, '201017', 'APP_IMPORT_FILE_FORMAT_ERROR', 'application import file format error', 'en', '', 'admin', 1724030366000); +INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (215, '201017', 'APP_IMPORT_FILE_FORMAT_ERROR', '导入文件格式错误', 'zh', '', 'admin', 1724030366000); SET FOREIGN_KEY_CHECKS = 1;