diff --git a/base/src/main/java/com/tinyengine/it/common/enums/Enums.java b/base/src/main/java/com/tinyengine/it/common/enums/Enums.java index e9b7f2ad..c534de21 100644 --- a/base/src/main/java/com/tinyengine/it/common/enums/Enums.java +++ b/base/src/main/java/com/tinyengine/it/common/enums/Enums.java @@ -908,4 +908,99 @@ public String getValue() { return value; } } + + public enum FileType { + /** + * File type zip. + */ + ZIP("application/zip"), + + /** + * File type x-zip. + */ + XZIP("application/x-zip-compressed"), + + /** + * File type json. + */ + JSON("application/json"), + + /** + * File type text. + */ + TXT("text/plain"), + + /** + * File type html. + */ + HTML("text/html"), + /** + * File type png. + */ + PNG("image/png"), + + /** + * File type jpg. + */ + JPG("image/jpeg"); + private final String value; + + FileType(String value) { + this.value = value; + } + + /** + * Gets value. + * + * @return the value + */ + public String getValue() { + return value; + } + } + + public enum FileNameEnd { + /** + * File name end .zip. + */ + ZIP(".zip"), + + /** + * File name end .json. + */ + JSON(".json"), + + /** + * File name end .text. + */ + TXT(".txt"), + + /** + * File name end .html. + */ + HTML(".html"), + /** + * File name end .png. + */ + PNG(".png"), + + /** + * File name end .jpg. + */ + JPG(".jpeg"); + private final String value; + + FileNameEnd(String value) { + this.value = value; + } + + /** + * Gets value. + * + * @return the value + */ + public String getValue() { + return value; + } + } } diff --git a/base/src/main/java/com/tinyengine/it/common/utils/SecurityFileCheckUtil.java b/base/src/main/java/com/tinyengine/it/common/utils/SecurityFileCheckUtil.java index 8687e99a..deae55e3 100644 --- a/base/src/main/java/com/tinyengine/it/common/utils/SecurityFileCheckUtil.java +++ b/base/src/main/java/com/tinyengine/it/common/utils/SecurityFileCheckUtil.java @@ -12,12 +12,15 @@ package com.tinyengine.it.common.utils; import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.databind.ObjectMapper; import com.tinyengine.it.common.exception.ExceptionEnum; import com.tinyengine.it.common.exception.ServiceException; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; +import java.io.IOException; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -59,14 +62,18 @@ public static boolean checkPathHasCrossDir(String dirOrFileName) { * @param fileTypeMap the fileTypeMap * @return true or false */ - public static boolean checkFileType(MultipartFile file, Map fileTypeMap) { + public static boolean checkFileType(MultipartFile file, Map> fileTypeMap) { if (Objects.isNull(file) || fileTypeMap.isEmpty()) { throw new ServiceException(ExceptionEnum.CM307.getResultCode(), ExceptionEnum.CM307.getResultMsg()); } String originalFileName = file.getOriginalFilename(); - for (Map.Entry entry : fileTypeMap.entrySet()) { + String contentType = file.getContentType(); + + for (Map.Entry> entry : fileTypeMap.entrySet()) { if (originalFileName.endsWith(entry.getKey())) { - return checkFileType(file, entry.getKey(), entry.getValue()); + if (entry.getValue().contains(contentType)) { + return true; + } } } return false; @@ -177,5 +184,19 @@ private static String getFileName(String filePath) { return file.getName(); } + /** + * Verify json file. + * + * @param file the file + */ + public static void isValidJson(MultipartFile file) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 将 MultipartFile 转换为 InputStream 并解析 JSON + objectMapper.readTree(file.getInputStream()); + } catch (IOException e) { + throw new ServiceException(ExceptionEnum.CM308.getResultCode(), ExceptionEnum.CM308.getResultMsg()); + } + } } diff --git a/base/src/main/java/com/tinyengine/it/controller/ComponentController.java b/base/src/main/java/com/tinyengine/it/controller/ComponentController.java index b4b0b109..dabeb230 100644 --- a/base/src/main/java/com/tinyengine/it/controller/ComponentController.java +++ b/base/src/main/java/com/tinyengine/it/controller/ComponentController.java @@ -13,6 +13,7 @@ package com.tinyengine.it.controller; import com.tinyengine.it.common.base.Result; +import com.tinyengine.it.common.enums.Enums; import com.tinyengine.it.common.exception.ExceptionEnum; import com.tinyengine.it.common.log.SystemControllerLog; import com.tinyengine.it.common.utils.SecurityFileCheckUtil; @@ -74,6 +75,12 @@ public Result bundleCreateComponent(@RequestParam MultipartFile file return Result.failed(ExceptionEnum.CM307); } SecurityFileCheckUtil.validFileName(file.getOriginalFilename()); + boolean checkFileType = SecurityFileCheckUtil.checkFileType(file, Enums.FileNameEnd.JSON.getValue(), + Enums.FileType.JSON.getValue()); + if (!checkFileType) { + return Result.failed(ExceptionEnum.CM308); + } + SecurityFileCheckUtil.isValidJson(file); // 返回插入和更新的条数 return componentService.readFileAndBulkCreate(file); } @@ -98,6 +105,12 @@ public Result bundleSplit(@RequestParam MultipartFile file) { return Result.failed(ExceptionEnum.CM307); } SecurityFileCheckUtil.validFileName(file.getOriginalFilename()); + boolean checkFileType = SecurityFileCheckUtil.checkFileType(file, Enums.FileNameEnd.JSON.getValue(), + Enums.FileType.JSON.getValue()); + if (!checkFileType) { + return Result.failed(ExceptionEnum.CM308); + } + SecurityFileCheckUtil.isValidJson(file); return componentService.bundleSplit(file); } diff --git a/base/src/main/java/com/tinyengine/it/controller/I18nEntryController.java b/base/src/main/java/com/tinyengine/it/controller/I18nEntryController.java index f16a2248..7894f254 100644 --- a/base/src/main/java/com/tinyengine/it/controller/I18nEntryController.java +++ b/base/src/main/java/com/tinyengine/it/controller/I18nEntryController.java @@ -13,6 +13,7 @@ package com.tinyengine.it.controller; import com.tinyengine.it.common.base.Result; +import com.tinyengine.it.common.enums.Enums; import com.tinyengine.it.common.exception.ExceptionEnum; import com.tinyengine.it.common.exception.ServiceException; import com.tinyengine.it.common.log.SystemControllerLog; @@ -46,6 +47,8 @@ import org.springframework.web.multipart.MultipartFile; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -248,7 +251,14 @@ public Result updateI18nSingleFile( if (file.isEmpty()) { return Result.failed(ExceptionEnum.CM307); } + Map> fileTypeMap = new HashMap<>(); + fileTypeMap.put(Enums.FileNameEnd.ZIP.getValue(), Arrays.asList(Enums.FileType.ZIP.getValue(), Enums.FileType.XZIP.getValue())); + fileTypeMap.put(Enums.FileNameEnd.JSON.getValue(), Arrays.asList(Enums.FileType.JSON.getValue())); SecurityFileCheckUtil.validFileName(file.getOriginalFilename()); + boolean checkFileType = SecurityFileCheckUtil.checkFileType(file, fileTypeMap); + if (!checkFileType) { + return Result.failed(ExceptionEnum.CM325); + } // 返回插入和更新的条数 result = i18nEntryService.readSingleFileAndBulkCreate(file, id); } @@ -285,6 +295,11 @@ public Result updateI18nMultiFile( return Result.failed(ExceptionEnum.CM307); } SecurityFileCheckUtil.validFileName(file.getOriginalFilename()); + boolean checkFileType = SecurityFileCheckUtil.checkFileType(file, Enums.FileNameEnd.JSON.getValue(), + Enums.FileType.JSON.getValue()); + if (!checkFileType) { + return Result.failed(ExceptionEnum.CM308); + } // 返回插入和更新的条数 result = i18nEntryService.readFilesAndbulkCreate(key, file, id); } diff --git a/base/src/main/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImpl.java b/base/src/main/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImpl.java index 88d6c109..4ade2134 100644 --- a/base/src/main/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImpl.java +++ b/base/src/main/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImpl.java @@ -21,6 +21,7 @@ import com.tinyengine.it.common.exception.ExceptionEnum; import com.tinyengine.it.common.exception.ServiceException; import com.tinyengine.it.common.log.SystemServiceLog; +import com.tinyengine.it.common.utils.SecurityFileCheckUtil; import com.tinyengine.it.common.utils.Utils; import com.tinyengine.it.mapper.I18nEntryMapper; import com.tinyengine.it.mapper.I18nLangMapper; @@ -326,7 +327,8 @@ public Result readSingleFileAndBulkCreate(MultipartFile file, int ho List entriesArr = new ArrayList<>(); String contentType = file.getContentType(); - if (Objects.equals(contentType, Enums.MimeType.JSON.getValue())) { + if (Objects.equals(contentType, Enums.FileType.JSON.getValue())) { + SecurityFileCheckUtil.isValidJson(file); Result parseJsonFileStreamResult = Utils.parseJsonFileStream(file); if (!parseJsonFileStreamResult.isSuccess()) { return Result.failed(ExceptionEnum.CM001); @@ -357,6 +359,7 @@ public Result readSingleFileAndBulkCreate(MultipartFile file, int ho @SystemServiceLog(description = "readFilesAndbulkCreate 批量上传词条数据") @Override public Result readFilesAndbulkCreate(String lang, MultipartFile file, int host) throws Exception { + SecurityFileCheckUtil.isValidJson(file); Result parseJsonFileStreamResult = Utils.parseJsonFileStream(file); // 解析 JSON 数据 if (!parseJsonFileStreamResult.isSuccess()) { diff --git a/base/src/main/java/com/tinyengine/it/service/material/impl/ComponentServiceImpl.java b/base/src/main/java/com/tinyengine/it/service/material/impl/ComponentServiceImpl.java index 2b7b7abd..ab7449d1 100644 --- a/base/src/main/java/com/tinyengine/it/service/material/impl/ComponentServiceImpl.java +++ b/base/src/main/java/com/tinyengine/it/service/material/impl/ComponentServiceImpl.java @@ -183,11 +183,6 @@ public Result readFileAndBulkCreate(MultipartFile file) { @Override @SystemServiceLog(description = "bundleSplit 拆分bundle.json实现方法") public Result bundleSplit(MultipartFile file) { - // 检验文件 - boolean isFileCheck = this.checkFile(file); - if (!isFileCheck) { - return Result.failed(ExceptionEnum.CM325); - } // 获取bundle.json数据 Result result = Utils.parseJsonFileStream(file); if (!result.isSuccess()) { @@ -392,13 +387,4 @@ private List buildComponentList(BundleDto bundleDto, List fileTypeMap = new HashMap<>(); - fileTypeMap.put(".json", "application/json"); - boolean isCheckFileType = SecurityFileCheckUtil.checkFileType(file, fileTypeMap); - if (!isCheckFileType) { - return false; - } - return true; - } } diff --git a/base/src/test/java/com/tinyengine/it/controller/I18nEntryControllerTest.java b/base/src/test/java/com/tinyengine/it/controller/I18nEntryControllerTest.java index 0068ef75..9fbdc1dd 100644 --- a/base/src/test/java/com/tinyengine/it/controller/I18nEntryControllerTest.java +++ b/base/src/test/java/com/tinyengine/it/controller/I18nEntryControllerTest.java @@ -17,6 +17,7 @@ import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; +import cn.hutool.core.io.IoUtil; import com.tinyengine.it.common.base.Result; import com.tinyengine.it.model.dto.DeleteI18nEntry; import com.tinyengine.it.model.dto.FileResult; @@ -36,6 +37,7 @@ import org.mockito.MockitoAnnotations; import org.springframework.web.multipart.MultipartFile; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -130,10 +132,13 @@ void testUpdateI18nSingleFile() throws Exception { Result mockData = new Result<>(); mockData.setSuccess(true); when(i18nEntryService.readSingleFileAndBulkCreate(any(MultipartFile.class), anyInt())) - .thenReturn(mockData); + .thenReturn(mockData); MultipartFile file = Mockito.mock(MultipartFile.class); - when(file.getOriginalFilename()).thenReturn("example.json"); - when(file.isEmpty()).thenReturn(false); + when(file.getContentType()).thenReturn("application/json"); + when(file.getOriginalFilename()).thenReturn("originalName.json"); + when(file.getName()).thenReturn("123"); + when(file.getBytes()).thenReturn("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8)); + when(file.getInputStream()).thenReturn(IoUtil.toStream("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8))); HashMap filesMap = new HashMap() {{ put("filesMap", file); }}; @@ -145,10 +150,13 @@ void testUpdateI18nSingleFile() throws Exception { @Test void testUpdateI18nMultiFile() throws Exception { when(i18nEntryService.readFilesAndbulkCreate(anyString(), any(MultipartFile.class), anyInt())) - .thenReturn(new Result()); + .thenReturn(new Result()); MultipartFile file = Mockito.mock(MultipartFile.class); - when(file.getOriginalFilename()).thenReturn("example.json"); - when(file.isEmpty()).thenReturn(false); + when(file.getContentType()).thenReturn("application/json"); + when(file.getOriginalFilename()).thenReturn("originalName.json"); + when(file.getName()).thenReturn("123"); + when(file.getBytes()).thenReturn("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8)); + when(file.getInputStream()).thenReturn(IoUtil.toStream("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8))); HashMap filesMap = new HashMap() {{ put("filesMap", file); }}; diff --git a/base/src/test/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImplTest.java b/base/src/test/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImplTest.java index c2de3384..8ca96f85 100644 --- a/base/src/test/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImplTest.java +++ b/base/src/test/java/com/tinyengine/it/service/app/impl/I18nEntryServiceImplTest.java @@ -284,7 +284,7 @@ void testReadSingleFileAndBulkCreate() throws Exception { when(file.getOriginalFilename()).thenReturn("originalName"); when(file.getName()).thenReturn("123"); when(file.getBytes()).thenReturn("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8)); - when(file.getInputStream()).thenReturn(IoUtil.toStream("test".getBytes(StandardCharsets.UTF_8))); + when(file.getInputStream()).thenReturn(IoUtil.toStream("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8))); Result result = i18nEntryServiceImpl.readSingleFileAndBulkCreate(file, 0); @@ -299,7 +299,7 @@ void testReadFilesAndbulkCreate() throws Exception { when(file.getOriginalFilename()).thenReturn("originalName"); when(file.getName()).thenReturn("123"); when(file.getBytes()).thenReturn("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8)); - when(file.getInputStream()).thenReturn(IoUtil.toStream("test".getBytes(StandardCharsets.UTF_8))); + when(file.getInputStream()).thenReturn(IoUtil.toStream("{\"name\":\"value\"}".getBytes(StandardCharsets.UTF_8))); // file not existed Result result = i18nEntryServiceImpl.readFilesAndbulkCreate("1", file, 0); Assertions.assertNull(result.getData());