From 0a7183c09156d72035d1f4aade273f191e1baa35 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Mon, 9 Dec 2024 14:56:41 +0300 Subject: [PATCH 01/11] SUPPORT-8771:init av-service --- .gitignore | 1 + pom.xml | 55 +++++++++++++ .../av/service/AvServiceApplication.java | 13 +++ .../controller/FileScanController.java | 38 +++++++++ .../micord/av/service/model/AvResponse.java | 17 ++++ .../av/service/service/FileScanService.java | 79 +++++++++++++++++++ .../ru/micord/av/service/util/AvUtils.java | 62 +++++++++++++++ src/main/resources/application.properties | 3 + 8 files changed, 268 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/ru/micord/av/service/AvServiceApplication.java create mode 100644 src/main/java/ru/micord/av/service/controller/FileScanController.java create mode 100644 src/main/java/ru/micord/av/service/model/AvResponse.java create mode 100644 src/main/java/ru/micord/av/service/service/FileScanService.java create mode 100644 src/main/java/ru/micord/av/service/util/AvUtils.java create mode 100644 src/main/resources/application.properties diff --git a/.gitignore b/.gitignore index 549e00a..8f922b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ HELP.md + target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f267431 --- /dev/null +++ b/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.0 + + + ru.micord.av.service + av-service + 0.0.1-SNAPSHOT + av-service + av-service + + + + + + + + + + + + + + + 17 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/ru/micord/av/service/AvServiceApplication.java b/src/main/java/ru/micord/av/service/AvServiceApplication.java new file mode 100644 index 0000000..7fe9aa8 --- /dev/null +++ b/src/main/java/ru/micord/av/service/AvServiceApplication.java @@ -0,0 +1,13 @@ +package ru.micord.av.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AvServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(AvServiceApplication.class, args); + } + +} diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java new file mode 100644 index 0000000..00b4d94 --- /dev/null +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -0,0 +1,38 @@ +package ru.micord.av.service.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; +import ru.micord.av.service.model.AvResponse; +import ru.micord.av.service.service.FileScanService; + +/** + * @author Adel Kalimullin + */ +@RestController +@RequestMapping("/scans") +public class FileScanController { + private final FileScanService fileScanService; + + public FileScanController(FileScanService fileScanService) { + this.fileScanService = fileScanService; + } + + @PostMapping() + public ResponseEntity scanFile( @RequestParam("file") MultipartFile file) { + if (file.isEmpty()) { + return ResponseEntity.badRequest().build(); + } + try { + AvResponse result = fileScanService.scanFile(file); + return ResponseEntity.ok(result); + } + catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } +} diff --git a/src/main/java/ru/micord/av/service/model/AvResponse.java b/src/main/java/ru/micord/av/service/model/AvResponse.java new file mode 100644 index 0000000..3acab86 --- /dev/null +++ b/src/main/java/ru/micord/av/service/model/AvResponse.java @@ -0,0 +1,17 @@ +package ru.micord.av.service.model; + +import java.util.Map; + +/** + * @author Adel Kalimullin + */ +public record AvResponse(String completed, String created, Integer progress, + Map scan_result, String status, String[] verdicts) { + public record Scan(String started, String stopped, Threat[] threats, String verdict) { + public static final String VERDICT_CLEAN = "clean"; + public static final String VERDICT_INFECTED = "infected"; + + public record Threat(String name, String object) { + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/micord/av/service/service/FileScanService.java b/src/main/java/ru/micord/av/service/service/FileScanService.java new file mode 100644 index 0000000..4e1278e --- /dev/null +++ b/src/main/java/ru/micord/av/service/service/FileScanService.java @@ -0,0 +1,79 @@ +package ru.micord.av.service.service; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import ru.micord.av.service.model.AvResponse; +import ru.micord.av.service.util.AvUtils; + +/** + * @author Adel Kalimullin + */ +@Service +public class FileScanService { + @Value("${file.upload.directory}") + public String uploadDirectory; + + public AvResponse scanFile(MultipartFile file){ + File tempFile = null; + LocalDateTime startTime; + LocalDateTime stopTime; + try { + tempFile = saveFile(file); + startTime = LocalDateTime.now(); + String rawResult = runKeslScan(tempFile); + stopTime = LocalDateTime.now(); + return AvUtils.parseKeslResponse(rawResult, startTime, stopTime,tempFile,file.getOriginalFilename()); + } + catch (Exception e) { + throw new RuntimeException("Ошибка при сканировании файла: " + file.getOriginalFilename(), e); + } + finally { + deleteFile(tempFile); + } + } + + private File saveFile(MultipartFile file) throws IOException { + Path uploadPath = Paths.get(uploadDirectory); + if (!Files.exists(uploadPath)) { + Files.createDirectories(uploadPath); + } + Path tempFile = Files.createTempFile(uploadPath, "kesl-upload-", ".tmp"); + file.transferTo(tempFile.toFile()); + return tempFile.toFile(); + } + + private String runKeslScan(File file) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder( + AvUtils.KESL_CONTROL, + AvUtils.KESL_SCAN, + file.getAbsolutePath() + ); + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + try (InputStream inputStream = process.getInputStream()) { + String result = new String(inputStream.readAllBytes()); + process.waitFor(); + return result; + } + } + + private void deleteFile(File file) { + if (file != null && file.exists()) { + try { + Files.delete(file.toPath()); + } + catch (IOException e) { + throw new RuntimeException("Ошибка удаления временного файла: " + file.getAbsolutePath(), e); + } + } + } +} diff --git a/src/main/java/ru/micord/av/service/util/AvUtils.java b/src/main/java/ru/micord/av/service/util/AvUtils.java new file mode 100644 index 0000000..7272d23 --- /dev/null +++ b/src/main/java/ru/micord/av/service/util/AvUtils.java @@ -0,0 +1,62 @@ +package ru.micord.av.service.util; + +import java.io.File; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ru.micord.av.service.model.AvResponse; + +/** + * @author Adel Kalimullin + */ +public class AvUtils { + + public static String KESL_CONTROL = "kesl-control"; + public static String KESL_SCAN = "--scan-file"; + + public static AvResponse parseKeslResponse(String rawResult, LocalDateTime startTime, + LocalDateTime stopTime, File file, String originalFilename) { + Map scanResults = new HashMap<>(); + List verdicts = new ArrayList<>(); + List threats = new ArrayList<>(); + String verdict = null; + + for (String line : rawResult.split("\n")) { + if (line.startsWith("Infected objects")) { + verdict = extractInteger(line) > 0 + ? AvResponse.Scan.VERDICT_INFECTED + : AvResponse.Scan.VERDICT_CLEAN; + if (AvResponse.Scan.VERDICT_INFECTED.equals(verdict)) + threats.add(new AvResponse.Scan.Threat("", file.getAbsolutePath())); + } + if (line.startsWith("Scan errors") && extractInteger(line) > 0) { + verdict = "error"; + } + } + if (verdict != null) { + scanResults.put(originalFilename, new AvResponse.Scan(startTime.toString(), stopTime.toString(), + threats.toArray(new AvResponse.Scan.Threat[0]), verdict + )); + verdicts.add(verdict); + } + return new AvResponse(startTime.toString(), stopTime.toString(), 100, scanResults, "completed", + verdicts.toArray(new String[0]) + ); + } + + private static int extractInteger(String line) { + String[] parts = line.split(":"); + if (parts.length > 1) { + try { + return Integer.parseInt(parts[1].trim()); + } + catch (NumberFormatException e) { + throw new RuntimeException(e); + } + } + return 0; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..40a8f84 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=ervu-lkrp-kesl +server.port=8080 +file.upload.directory = /tmp/uploaded_files From c1efb1bca07499a62f8e2f8058f36dd8ba4c54ec Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Mon, 9 Dec 2024 16:21:38 +0300 Subject: [PATCH 02/11] SUPPORT-8771:fix --- src/main/java/ru/micord/av/service/util/AvUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/micord/av/service/util/AvUtils.java b/src/main/java/ru/micord/av/service/util/AvUtils.java index 7272d23..48a87b7 100644 --- a/src/main/java/ru/micord/av/service/util/AvUtils.java +++ b/src/main/java/ru/micord/av/service/util/AvUtils.java @@ -4,8 +4,9 @@ import java.io.File; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.List; + import ru.micord.av.service.model.AvResponse; From c051a76d59efbce2c797906b17290bc2230919f4 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Mon, 9 Dec 2024 16:39:52 +0300 Subject: [PATCH 03/11] SUPPORT-8771:fix by review --- .../av/service/exception/AvException.java | 14 ++++++++++++++ .../av/service/service/FileScanService.java | 17 +++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 src/main/java/ru/micord/av/service/exception/AvException.java diff --git a/src/main/java/ru/micord/av/service/exception/AvException.java b/src/main/java/ru/micord/av/service/exception/AvException.java new file mode 100644 index 0000000..4dcff5a --- /dev/null +++ b/src/main/java/ru/micord/av/service/exception/AvException.java @@ -0,0 +1,14 @@ +package ru.micord.av.service.exception; + +/** + * @author Adel Kalimullin + */ +public class AvException extends RuntimeException { + public AvException(String message) { + super(message); + } + + public AvException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/ru/micord/av/service/service/FileScanService.java b/src/main/java/ru/micord/av/service/service/FileScanService.java index 4e1278e..8e8328c 100644 --- a/src/main/java/ru/micord/av/service/service/FileScanService.java +++ b/src/main/java/ru/micord/av/service/service/FileScanService.java @@ -11,6 +11,7 @@ import java.time.LocalDateTime; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import ru.micord.av.service.exception.AvException; import ru.micord.av.service.model.AvResponse; import ru.micord.av.service.util.AvUtils; @@ -22,7 +23,7 @@ public class FileScanService { @Value("${file.upload.directory}") public String uploadDirectory; - public AvResponse scanFile(MultipartFile file){ + public AvResponse scanFile(MultipartFile file) { File tempFile = null; LocalDateTime startTime; LocalDateTime stopTime; @@ -31,10 +32,12 @@ public class FileScanService { startTime = LocalDateTime.now(); String rawResult = runKeslScan(tempFile); stopTime = LocalDateTime.now(); - return AvUtils.parseKeslResponse(rawResult, startTime, stopTime,tempFile,file.getOriginalFilename()); + return AvUtils.parseKeslResponse(rawResult, startTime, stopTime, tempFile, + file.getOriginalFilename() + ); } catch (Exception e) { - throw new RuntimeException("Ошибка при сканировании файла: " + file.getOriginalFilename(), e); + throw new AvException("Ошибка при сканировании файла: " + file.getOriginalFilename(), e); } finally { deleteFile(tempFile); @@ -52,9 +55,7 @@ public class FileScanService { } private String runKeslScan(File file) throws IOException, InterruptedException { - ProcessBuilder processBuilder = new ProcessBuilder( - AvUtils.KESL_CONTROL, - AvUtils.KESL_SCAN, + ProcessBuilder processBuilder = new ProcessBuilder(AvUtils.KESL_CONTROL, AvUtils.KESL_SCAN, file.getAbsolutePath() ); processBuilder.redirectErrorStream(true); @@ -66,13 +67,13 @@ public class FileScanService { } } - private void deleteFile(File file) { + private void deleteFile(File file) { if (file != null && file.exists()) { try { Files.delete(file.toPath()); } catch (IOException e) { - throw new RuntimeException("Ошибка удаления временного файла: " + file.getAbsolutePath(), e); + throw new AvException("Ошибка удаления временного файла: " + file.getAbsolutePath(), e); } } } From bb066af038978f2d1a069f7a781dc9451d8c651a Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 09:56:17 +0300 Subject: [PATCH 04/11] SUPPORT-8771:fix by review --- pom.xml | 16 +--------------- .../service/controller/FileScanController.java | 10 +++++++--- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index f267431..6178116 100644 --- a/pom.xml +++ b/pom.xml @@ -11,22 +11,8 @@ ru.micord.av.service av-service - 0.0.1-SNAPSHOT + 1.0.0-SNAPSHOT av-service - av-service - - - - - - - - - - - - - 17 diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index 00b4d94..ccf41bc 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -1,11 +1,13 @@ package ru.micord.av.service.controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import ru.micord.av.service.model.AvResponse; import ru.micord.av.service.service.FileScanService; @@ -14,8 +16,9 @@ import ru.micord.av.service.service.FileScanService; * @author Adel Kalimullin */ @RestController -@RequestMapping("/scans") +@RequestMapping("/av-wrapper") public class FileScanController { + private static final Logger LOGGER = LoggerFactory.getLogger(FileScanController.class); private final FileScanService fileScanService; public FileScanController(FileScanService fileScanService) { @@ -23,7 +26,7 @@ public class FileScanController { } @PostMapping() - public ResponseEntity scanFile( @RequestParam("file") MultipartFile file) { + public ResponseEntity scanFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest().build(); } @@ -32,6 +35,7 @@ public class FileScanController { return ResponseEntity.ok(result); } catch (Exception e) { + LOGGER.error(e.getMessage(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } From 9311fc6b9e22438bcf5f6d70c0e373b837b4b955 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 10:22:27 +0300 Subject: [PATCH 05/11] SUPPORT-8771:fix --- .../controller/FileScanController.java | 4 +- .../{AvResponse.java => ScanResult.java} | 2 +- .../av/service/service/FileManager.java | 42 +++++++++ .../av/service/service/FileScanService.java | 86 ++++++++++++------- .../ru/micord/av/service/util/AvUtils.java | 63 -------------- 5 files changed, 102 insertions(+), 95 deletions(-) rename src/main/java/ru/micord/av/service/model/{AvResponse.java => ScanResult.java} (88%) create mode 100644 src/main/java/ru/micord/av/service/service/FileManager.java delete mode 100644 src/main/java/ru/micord/av/service/util/AvUtils.java diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index ccf41bc..404387a 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import ru.micord.av.service.model.AvResponse; +import ru.micord.av.service.model.ScanResult; import ru.micord.av.service.service.FileScanService; /** @@ -31,7 +31,7 @@ public class FileScanController { return ResponseEntity.badRequest().build(); } try { - AvResponse result = fileScanService.scanFile(file); + ScanResult result = fileScanService.scanFile(file); return ResponseEntity.ok(result); } catch (Exception e) { diff --git a/src/main/java/ru/micord/av/service/model/AvResponse.java b/src/main/java/ru/micord/av/service/model/ScanResult.java similarity index 88% rename from src/main/java/ru/micord/av/service/model/AvResponse.java rename to src/main/java/ru/micord/av/service/model/ScanResult.java index 3acab86..2f9196f 100644 --- a/src/main/java/ru/micord/av/service/model/AvResponse.java +++ b/src/main/java/ru/micord/av/service/model/ScanResult.java @@ -5,7 +5,7 @@ import java.util.Map; /** * @author Adel Kalimullin */ -public record AvResponse(String completed, String created, Integer progress, +public record ScanResult(String completed, String created, Integer progress, Map scan_result, String status, String[] verdicts) { public record Scan(String started, String stopped, Threat[] threats, String verdict) { public static final String VERDICT_CLEAN = "clean"; diff --git a/src/main/java/ru/micord/av/service/service/FileManager.java b/src/main/java/ru/micord/av/service/service/FileManager.java new file mode 100644 index 0000000..71441f5 --- /dev/null +++ b/src/main/java/ru/micord/av/service/service/FileManager.java @@ -0,0 +1,42 @@ +package ru.micord.av.service.service; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import ru.micord.av.service.exception.AvException; + +/** + * @author Adel Kalimullin + */ +@Service +public class FileManager { + @Value("${file.upload.directory}") + public String uploadDirectory; + + public File saveFile(MultipartFile file) throws IOException { + Path uploadPath = Paths.get(uploadDirectory); + if (!Files.exists(uploadPath)) { + Files.createDirectories(uploadPath); + } + Path tempFile = Files.createTempFile(uploadPath, "kesl-upload-", ".tmp"); + file.transferTo(tempFile.toFile()); + return tempFile.toFile(); + } + + public void deleteFile(File file) { + if (file != null && file.exists()) { + try { + Files.delete(file.toPath()); + } + catch (IOException e) { + throw new AvException("Ошибка удаления временного файла: " + file.getAbsolutePath(), e); + } + } + } +} diff --git a/src/main/java/ru/micord/av/service/service/FileScanService.java b/src/main/java/ru/micord/av/service/service/FileScanService.java index 8e8328c..615938b 100644 --- a/src/main/java/ru/micord/av/service/service/FileScanService.java +++ b/src/main/java/ru/micord/av/service/service/FileScanService.java @@ -3,36 +3,40 @@ package ru.micord.av.service.service; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import ru.micord.av.service.exception.AvException; -import ru.micord.av.service.model.AvResponse; -import ru.micord.av.service.util.AvUtils; +import ru.micord.av.service.model.ScanResult; /** * @author Adel Kalimullin */ @Service public class FileScanService { - @Value("${file.upload.directory}") - public String uploadDirectory; + public static String KESL_CONTROL = "kesl-control"; + public static String KESL_SCAN = "--scan-file"; + private final FileManager fileManager; - public AvResponse scanFile(MultipartFile file) { + public FileScanService(FileManager fileManager) { + this.fileManager = fileManager; + } + + public ScanResult scanFile(MultipartFile file) { File tempFile = null; LocalDateTime startTime; LocalDateTime stopTime; try { - tempFile = saveFile(file); + tempFile = fileManager.saveFile(file); startTime = LocalDateTime.now(); String rawResult = runKeslScan(tempFile); stopTime = LocalDateTime.now(); - return AvUtils.parseKeslResponse(rawResult, startTime, stopTime, tempFile, + return parseKeslResponse(rawResult, startTime, stopTime, tempFile, file.getOriginalFilename() ); } @@ -40,22 +44,12 @@ public class FileScanService { throw new AvException("Ошибка при сканировании файла: " + file.getOriginalFilename(), e); } finally { - deleteFile(tempFile); + fileManager.deleteFile(tempFile); } } - private File saveFile(MultipartFile file) throws IOException { - Path uploadPath = Paths.get(uploadDirectory); - if (!Files.exists(uploadPath)) { - Files.createDirectories(uploadPath); - } - Path tempFile = Files.createTempFile(uploadPath, "kesl-upload-", ".tmp"); - file.transferTo(tempFile.toFile()); - return tempFile.toFile(); - } - private String runKeslScan(File file) throws IOException, InterruptedException { - ProcessBuilder processBuilder = new ProcessBuilder(AvUtils.KESL_CONTROL, AvUtils.KESL_SCAN, + ProcessBuilder processBuilder = new ProcessBuilder(KESL_CONTROL, KESL_SCAN, file.getAbsolutePath() ); processBuilder.redirectErrorStream(true); @@ -67,14 +61,48 @@ public class FileScanService { } } - private void deleteFile(File file) { - if (file != null && file.exists()) { - try { - Files.delete(file.toPath()); + private ScanResult parseKeslResponse(String rawResult, LocalDateTime startTime, + LocalDateTime stopTime, File file, String originalFilename) { + Map scanResults = new HashMap<>(); + List verdicts = new ArrayList<>(); + List threats = new ArrayList<>(); + String verdict = null; + + for (String line : rawResult.split("\n")) { + if (line.startsWith("Infected objects")) { + verdict = extractInteger(line) > 0 + ? ScanResult.Scan.VERDICT_INFECTED + : ScanResult.Scan.VERDICT_CLEAN; + if (ScanResult.Scan.VERDICT_INFECTED.equals(verdict)) + threats.add(new ScanResult.Scan.Threat("", file.getAbsolutePath())); } - catch (IOException e) { - throw new AvException("Ошибка удаления временного файла: " + file.getAbsolutePath(), e); + if (line.startsWith("Scan errors") && extractInteger(line) > 0) { + verdict = "error"; } } + if (verdict != null) { + scanResults.put(originalFilename, + new ScanResult.Scan(startTime.toString(), stopTime.toString(), + threats.toArray(new ScanResult.Scan.Threat[0]), verdict + ) + ); + verdicts.add(verdict); + } + return new ScanResult(startTime.toString(), stopTime.toString(), 100, scanResults, "completed", + verdicts.toArray(new String[0]) + ); + } + + private int extractInteger(String line) { + String[] parts = line.split(":"); + if (parts.length > 1) { + try { + return Integer.parseInt(parts[1].trim()); + } + catch (NumberFormatException e) { + throw new RuntimeException(e); + } + } + return 0; } } diff --git a/src/main/java/ru/micord/av/service/util/AvUtils.java b/src/main/java/ru/micord/av/service/util/AvUtils.java deleted file mode 100644 index 48a87b7..0000000 --- a/src/main/java/ru/micord/av/service/util/AvUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -package ru.micord.av.service.util; - -import java.io.File; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.List; - - -import ru.micord.av.service.model.AvResponse; - -/** - * @author Adel Kalimullin - */ -public class AvUtils { - - public static String KESL_CONTROL = "kesl-control"; - public static String KESL_SCAN = "--scan-file"; - - public static AvResponse parseKeslResponse(String rawResult, LocalDateTime startTime, - LocalDateTime stopTime, File file, String originalFilename) { - Map scanResults = new HashMap<>(); - List verdicts = new ArrayList<>(); - List threats = new ArrayList<>(); - String verdict = null; - - for (String line : rawResult.split("\n")) { - if (line.startsWith("Infected objects")) { - verdict = extractInteger(line) > 0 - ? AvResponse.Scan.VERDICT_INFECTED - : AvResponse.Scan.VERDICT_CLEAN; - if (AvResponse.Scan.VERDICT_INFECTED.equals(verdict)) - threats.add(new AvResponse.Scan.Threat("", file.getAbsolutePath())); - } - if (line.startsWith("Scan errors") && extractInteger(line) > 0) { - verdict = "error"; - } - } - if (verdict != null) { - scanResults.put(originalFilename, new AvResponse.Scan(startTime.toString(), stopTime.toString(), - threats.toArray(new AvResponse.Scan.Threat[0]), verdict - )); - verdicts.add(verdict); - } - return new AvResponse(startTime.toString(), stopTime.toString(), 100, scanResults, "completed", - verdicts.toArray(new String[0]) - ); - } - - private static int extractInteger(String line) { - String[] parts = line.split(":"); - if (parts.length > 1) { - try { - return Integer.parseInt(parts[1].trim()); - } - catch (NumberFormatException e) { - throw new RuntimeException(e); - } - } - return 0; - } -} From ed4437054e1e425575005aba4db692eb2fb101d4 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 10:28:49 +0300 Subject: [PATCH 06/11] SUPPORT-8771:fix --- .../ru/micord/av/service/controller/FileScanController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index 404387a..b1abe3b 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -25,7 +25,7 @@ public class FileScanController { this.fileScanService = fileScanService; } - @PostMapping() + @PostMapping("/scan-file") public ResponseEntity scanFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest().build(); From 965a90549bae4b001bdf32264f3478cefd108213 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 11:25:44 +0300 Subject: [PATCH 07/11] SUPPORT-8771:add mock param --- .../micord/av/service/controller/FileScanController.java | 8 +++----- src/main/resources/application.properties | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index b1abe3b..e167736 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -4,10 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import ru.micord.av.service.model.ScanResult; import ru.micord.av.service.service.FileScanService; @@ -26,7 +23,8 @@ public class FileScanController { } @PostMapping("/scan-file") - public ResponseEntity scanFile(@RequestParam("file") MultipartFile file) { + public ResponseEntity scanFile(@RequestPart("file") MultipartFile file, + @RequestParam(value = "wait", required = false, defaultValue = "0") long wait) { if (file.isEmpty()) { return ResponseEntity.badRequest().build(); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 40a8f84..ee7a3e8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1 @@ -spring.application.name=ervu-lkrp-kesl -server.port=8080 file.upload.directory = /tmp/uploaded_files From eb555fdcb7e1535f52a868f1f989e9f246a58c34 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 13:57:12 +0300 Subject: [PATCH 08/11] SUPPORT-8771:check exitCode --- .../java/ru/micord/av/service/service/FileScanService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/ru/micord/av/service/service/FileScanService.java b/src/main/java/ru/micord/av/service/service/FileScanService.java index 615938b..701ad31 100644 --- a/src/main/java/ru/micord/av/service/service/FileScanService.java +++ b/src/main/java/ru/micord/av/service/service/FileScanService.java @@ -57,6 +57,10 @@ public class FileScanService { try (InputStream inputStream = process.getInputStream()) { String result = new String(inputStream.readAllBytes()); process.waitFor(); + int exitCode = process.waitFor(); + if (exitCode != 0 && exitCode != 72) { + throw new AvException("Ошибка KESL, код завершения: " + exitCode); + } return result; } } From 59ad00fab4f6551f94cca2af85e5a92db7ae09a2 Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 14:16:25 +0300 Subject: [PATCH 09/11] SUPPORT-8771:fix --- .../ru/micord/av/service/controller/FileScanController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index e167736..7282e40 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -23,8 +23,7 @@ public class FileScanController { } @PostMapping("/scan-file") - public ResponseEntity scanFile(@RequestPart("file") MultipartFile file, - @RequestParam(value = "wait", required = false, defaultValue = "0") long wait) { + public ResponseEntity scanFile(@RequestPart("file") MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest().build(); } From d263982be1b7fc2dd65e673505f1f7ca216cf73a Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Tue, 10 Dec 2024 14:18:17 +0300 Subject: [PATCH 10/11] SUPPORT-8771:fixes --- .../ru/micord/av/service/controller/FileScanController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/micord/av/service/controller/FileScanController.java b/src/main/java/ru/micord/av/service/controller/FileScanController.java index 7282e40..f947fe4 100644 --- a/src/main/java/ru/micord/av/service/controller/FileScanController.java +++ b/src/main/java/ru/micord/av/service/controller/FileScanController.java @@ -4,7 +4,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import ru.micord.av.service.model.ScanResult; import ru.micord.av.service.service.FileScanService; From 7e70b860cbfb9f3144aae46415db0b31c2dd957c Mon Sep 17 00:00:00 2001 From: "adel.kalimullin" Date: Wed, 11 Dec 2024 08:41:58 +0300 Subject: [PATCH 11/11] SUPPORT-8771:fix --- src/main/java/ru/micord/av/service/service/FileScanService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/micord/av/service/service/FileScanService.java b/src/main/java/ru/micord/av/service/service/FileScanService.java index 701ad31..e7f85d2 100644 --- a/src/main/java/ru/micord/av/service/service/FileScanService.java +++ b/src/main/java/ru/micord/av/service/service/FileScanService.java @@ -56,7 +56,6 @@ public class FileScanService { Process process = processBuilder.start(); try (InputStream inputStream = process.getInputStream()) { String result = new String(inputStream.readAllBytes()); - process.waitFor(); int exitCode = process.waitFor(); if (exitCode != 0 && exitCode != 72) { throw new AvException("Ошибка KESL, код завершения: " + exitCode);