SUPPORT-8771:fix
This commit is contained in:
parent
bb066af038
commit
9311fc6b9e
5 changed files with 102 additions and 95 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<String, Scan> scan_result, String status, String[] verdicts) {
|
||||
public record Scan(String started, String stopped, Threat[] threats, String verdict) {
|
||||
public static final String VERDICT_CLEAN = "clean";
|
||||
42
src/main/java/ru/micord/av/service/service/FileManager.java
Normal file
42
src/main/java/ru/micord/av/service/service/FileManager.java
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, ScanResult.Scan> scanResults = new HashMap<>();
|
||||
List<String> verdicts = new ArrayList<>();
|
||||
List<ScanResult.Scan.Threat> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String, AvResponse.Scan> scanResults = new HashMap<>();
|
||||
List<String> verdicts = new ArrayList<>();
|
||||
List<AvResponse.Scan.Threat> 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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue