From 0a8b4fab74e0701f58572cf9628c077c69c048a0 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sun, 14 Mar 2021 18:26:53 +0100 Subject: [PATCH] #419 - check filex extension on server and reject invalid ones --- .../budgetmaster/images/ImageService.java | 16 +++++++++++++--- .../images/InvalidFileExtensionException.java | 9 +++++++++ .../budgetmaster/images/MediaController.java | 6 ++++++ src/main/resources/languages/base_de.properties | 1 + src/main/resources/languages/base_en.properties | 1 + 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/main/java/de/deadlocker8/budgetmaster/images/InvalidFileExtensionException.java diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java index 6dba1b714..0c414c8e5 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java +++ b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java @@ -1,6 +1,7 @@ package de.deadlocker8.budgetmaster.images; import de.deadlocker8.budgetmaster.services.Resetable; +import de.thecodelabs.utils.util.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -9,12 +10,14 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.util.List; import java.util.Optional; @Service public class ImageService implements Resetable { private static final Logger LOGGER = LoggerFactory.getLogger(ImageService.class); + private static final List<String> ALLOWED_IMAGE_EXTENSIONS = List.of("png", "jpeg", "jpg"); private final ImageRepository imageRepository; @@ -54,7 +57,7 @@ public class ImageService implements Resetable } @Transactional - public void saveImageFile(MultipartFile file) throws IOException + public void saveImageFile(MultipartFile file) throws IOException, InvalidFileExtensionException { Byte[] byteObjects = new Byte[file.getBytes().length]; @@ -70,11 +73,18 @@ public class ImageService implements Resetable throw new IllegalArgumentException("Could not determine file extension from file name: " + file.getOriginalFilename()); } - final Image image = new Image(byteObjects, fileExtensionOptional.get()); + final String fileExtension = fileExtensionOptional.get(); + if(!ALLOWED_IMAGE_EXTENSIONS.contains(fileExtension)) + { + throw new InvalidFileExtensionException(Localization.getString("upload.image.error.invalid.extension", fileExtension)); + } + + final Image image = new Image(byteObjects, fileExtension); imageRepository.save(image); } - private Optional<String> getFileExtension(String filename) { + private Optional<String> getFileExtension(String filename) + { return Optional.ofNullable(filename) .filter(f -> f.contains(".")) .map(f -> f.substring(filename.lastIndexOf(".") + 1)); diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/InvalidFileExtensionException.java b/src/main/java/de/deadlocker8/budgetmaster/images/InvalidFileExtensionException.java new file mode 100644 index 000000000..4b851655d --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/images/InvalidFileExtensionException.java @@ -0,0 +1,9 @@ +package de.deadlocker8.budgetmaster.images; + +public class InvalidFileExtensionException extends Exception +{ + public InvalidFileExtensionException(String s) + { + super(s); + } +} diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java b/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java index 41fb1c601..e460496ca 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java @@ -48,6 +48,12 @@ public class MediaController extends BaseController success = false; localizedMessage = Localization.getString("upload.image.error", e.getMessage()); } + catch(InvalidFileExtensionException e) + { + e.printStackTrace(); + success = false; + localizedMessage = e.getMessage(); + } final JsonObject data = new JsonObject(); data.addProperty("isUploadSuccessful", success); diff --git a/src/main/resources/languages/base_de.properties b/src/main/resources/languages/base_de.properties index e44b9ba91..dced80922 100644 --- a/src/main/resources/languages/base_de.properties +++ b/src/main/resources/languages/base_de.properties @@ -141,6 +141,7 @@ notification.settings.database.delete.success=Datenbank erfolgreich gelöscht notification.settings.database.import.success=Import erfolgreich: {0} Konten, {1} Buchungen, {2} Kategorien, {3} Vorlagen und {4} Diagramme upload.image.success=Erfolgreich hochgeladen upload.image.error=Fehler: {0} +upload.image.error.invalid.extension=Die Dateiendung "{0}" is nicht zugelassen für das Hochladen von Bildern # WARNING warning.text.account.delete=Das Konto "{0}" kann nicht gelöscht werden, da mindestens ein Konto existieren muss. Um dieses Konto zu löschen musst du zuerst ein neues anlegen. diff --git a/src/main/resources/languages/base_en.properties b/src/main/resources/languages/base_en.properties index cca8b4d17..f20c53071 100644 --- a/src/main/resources/languages/base_en.properties +++ b/src/main/resources/languages/base_en.properties @@ -141,6 +141,7 @@ notification.settings.database.delete.success=Successfully deleted database notification.settings.database.import.success=Import successful: {0} accounts, {1} transactions, {2} categories, {3} templates and {4} charts upload.image.success=Upload successful upload.image.error=Error: {0} +upload.image.error.invalid.extension=File extension "{0}" is not allowed for image upload # WARNING warning.text.account.delete=The account "{0}" could not be deleted, because at least one account must exist at all time. You have to create a new account in order to delete this one. -- GitLab