Re-update to 3.30.5
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 8m10s
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 8m10s
This commit is contained in:
@@ -2,13 +2,19 @@ package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||
import fr.titionfire.ffsaf.rest.exception.DetailException;
|
||||
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jodd.net.MimeTypes;
|
||||
import org.apache.tika.Tika;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -183,44 +189,72 @@ public class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static Future<String> replacePhoto(long id, byte[] input, String media, String dir) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (input == null || input.length == 0)
|
||||
return "OK";
|
||||
public static Uni<String> uploadFile(VirusScannerService ss, FileUpload file, long id, String media, String dir) {
|
||||
if (file == null || file.size() == 0)
|
||||
return Uni.createFrom().item("Ok");
|
||||
|
||||
try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) {
|
||||
String mimeType;
|
||||
try {
|
||||
Tika tika = new Tika();
|
||||
mimeType = tika.detect(is);// Magic.getMagicMatch(input, false).getMimeType();
|
||||
} catch (IOException e) {
|
||||
mimeType = URLConnection.guessContentTypeFromStream(is);
|
||||
}
|
||||
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false);
|
||||
if (detectedExtensions.length == 0)
|
||||
throw new IOException("Fail to detect file extension for MIME type " + mimeType);
|
||||
|
||||
File dirFile = new File(media, dir);
|
||||
if (!dirFile.exists())
|
||||
if (!dirFile.mkdirs())
|
||||
throw new IOException("Fail to create directory " + dir);
|
||||
|
||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||
File[] files = dirFile.listFiles(filter);
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
LOGGER.infof("Received file upload request for: %s (size: %d bytes)", file.fileName(), file.size());
|
||||
return Uni.createFrom().<InputStream>item(() -> {
|
||||
try {
|
||||
// Read the entire file into memory for virus scanning
|
||||
// ByteArrayInputStream fully supports mark/reset operations required by ClamAV
|
||||
// This ensures we can scan the file content before any filesystem storage
|
||||
InputStream fileStream = java.nio.file.Files.newInputStream(file.uploadedFile());
|
||||
byte[] fileBytes = fileStream.readAllBytes();
|
||||
fileStream.close(); // Close the file stream immediately
|
||||
return new ByteArrayInputStream(fileBytes);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to read uploaded file: " + e.getMessage(), e);
|
||||
}
|
||||
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool()).onItem()
|
||||
.transformToUni(inputStream -> {
|
||||
// Perform virus scanning reactively using the input stream
|
||||
return ss.scanFileReactive(file.fileName(), inputStream).onItem().invoke(() -> {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Warning: Failed to close input stream: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
})
|
||||
.onItem().transformToUni(scanResults -> Uni.createFrom().item(Unchecked.supplier(() -> {
|
||||
// Check if any scanner found a threat
|
||||
for (AntivirusScanResult result : scanResults) {
|
||||
if (result.getStatus() != Response.Status.OK.getStatusCode()) {
|
||||
LOGGER.warnf("THREAT DETECTED in %s: %s", file.fileName(), result.getMessage());
|
||||
throw new DetailException(Response.Status.fromStatusCode(result.getStatus()),
|
||||
"THREAT_DETECTED on File " + file.fileName() + " is infected: " + result.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String extension = "." + detectedExtensions[0];
|
||||
Files.write(new File(dirFile, id + extension).toPath(), input);
|
||||
return "OK";
|
||||
} catch (IOException e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
});
|
||||
// File is clean - now we can safely process it
|
||||
LOGGER.infof("File is clean: %s (size=%d) (contentType=%s)", file.fileName(), file.size(),
|
||||
file.contentType());
|
||||
|
||||
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(file.contentType(), false);
|
||||
if (detectedExtensions.length == 0)
|
||||
throw new DBadRequestException(
|
||||
"Fail to detect file extension for MIME type " + file.contentType());
|
||||
|
||||
File dirFile = new File(media, dir);
|
||||
if (!dirFile.exists())
|
||||
if (!dirFile.mkdirs())
|
||||
throw new DInternalError("Fail to create directory " + dir);
|
||||
|
||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||
File[] files = dirFile.listFiles(filter);
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
File f = file.filePath().toFile();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
f.renameTo(new File(dirFile, id + "." + detectedExtensions[0]));
|
||||
return "ok";
|
||||
})));
|
||||
}
|
||||
|
||||
public static Uni<Response> getMediaFile(long id, String media, String dirname,
|
||||
@@ -368,8 +402,8 @@ public class Utils {
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
public static String getFullName(Object ...models) {
|
||||
for (Object model : models){
|
||||
public static String getFullName(Object... models) {
|
||||
for (Object model : models) {
|
||||
if (model == null)
|
||||
continue;
|
||||
if (model instanceof MembreModel membreModel)
|
||||
|
||||
Reference in New Issue
Block a user