From fb7de87cda14ffc431f3ee5cd40876f9b9c47acd Mon Sep 17 00:00:00 2001 From: Tomasz Date: Wed, 3 Aug 2022 19:56:37 +0100 Subject: [PATCH 1/3] 1077 Set 4MB size limit for images --- src/main/java/ai/elimu/util/ImageHelper.java | 4 +++- .../content/multimedia/image/ImageCreateController.java | 9 ++++++++- src/main/webapp/WEB-INF/i18n/errors_en.properties | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/ai/elimu/util/ImageHelper.java b/src/main/java/ai/elimu/util/ImageHelper.java index 19dbe91e2..4f5b4c7fa 100644 --- a/src/main/java/ai/elimu/util/ImageHelper.java +++ b/src/main/java/ai/elimu/util/ImageHelper.java @@ -13,7 +13,9 @@ public class ImageHelper { public static final int MINIMUM_WIDTH = 640; - + + public static final int MAX_MB = 4194304; // 4MB + private static Logger logger = LogManager.getLogger(); /** diff --git a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java index 5c6057863..fe39d1112 100644 --- a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java +++ b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java @@ -40,6 +40,8 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor; +import static ai.elimu.util.ImageHelper.MAX_MB; + @Controller @RequestMapping("/content/multimedia/image/create") public class ImageCreateController { @@ -95,7 +97,7 @@ public String handleSubmit( } else { String originalFileName = multipartFile.getOriginalFilename(); logger.info("originalFileName: " + originalFileName); - + byte[] headerBytes = Arrays.copyOfRange(bytes, 0, 6); byte[] gifHeader87a = {71, 73, 70, 56, 55, 97}; // "GIF87a" byte[] gifHeader89a = {71, 73, 70, 56, 57, 97}; // "GIF89a" @@ -133,6 +135,11 @@ public String handleSubmit( } } } + + if (bytes.length > MAX_MB) { + result.rejectValue("bytes", "image.too.big"); + } + } } catch (IOException e) { logger.error(e); diff --git a/src/main/webapp/WEB-INF/i18n/errors_en.properties b/src/main/webapp/WEB-INF/i18n/errors_en.properties index 63b76e5be..9ee89092b 100644 --- a/src/main/webapp/WEB-INF/i18n/errors_en.properties +++ b/src/main/webapp/WEB-INF/i18n/errors_en.properties @@ -30,5 +30,6 @@ typeMismatch.thumbnail=Valid thumbnail format: PNG typeMismatch.java.lang.Integer={0} must be a number formatHint.Integer=Number (e.g. "5000") image.too.small=The image width must be at least 640px +image.too.big=The image size is too big emoji.unicode.version=Only emojis up to Unicode version 9 WordSpace=Spaces are not allowed From b8749354b59aa5781aae5b96ea170f2c334949fb Mon Sep 17 00:00:00 2001 From: Tomasz Date: Sun, 21 Aug 2022 17:00:17 +0100 Subject: [PATCH 2/3] 1077 Set 4MB size limit for images --- src/main/java/ai/elimu/util/ImageHelper.java | 2 +- .../web/content/multimedia/image/ImageCreateController.java | 6 +++--- src/main/webapp/WEB-INF/i18n/errors_en.properties | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/ai/elimu/util/ImageHelper.java b/src/main/java/ai/elimu/util/ImageHelper.java index 4f5b4c7fa..d8a035a99 100644 --- a/src/main/java/ai/elimu/util/ImageHelper.java +++ b/src/main/java/ai/elimu/util/ImageHelper.java @@ -14,7 +14,7 @@ public class ImageHelper { public static final int MINIMUM_WIDTH = 640; - public static final int MAX_MB = 4194304; // 4MB + public static final int MAX_BYTE_SIZE = 4194304; // 4MB private static Logger logger = LogManager.getLogger(); diff --git a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java index fe39d1112..1c80331c7 100644 --- a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java +++ b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java @@ -40,7 +40,7 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor; -import static ai.elimu.util.ImageHelper.MAX_MB; +import static ai.elimu.util.ImageHelper.MAX_BYTE_SIZE; @Controller @RequestMapping("/content/multimedia/image/create") @@ -136,8 +136,8 @@ public String handleSubmit( } } - if (bytes.length > MAX_MB) { - result.rejectValue("bytes", "image.too.big"); + if (bytes.length > MAX_BYTE_SIZE) { + result.rejectValue("bytes", "file.size.too.big"); } } diff --git a/src/main/webapp/WEB-INF/i18n/errors_en.properties b/src/main/webapp/WEB-INF/i18n/errors_en.properties index 9ee89092b..685db41c5 100644 --- a/src/main/webapp/WEB-INF/i18n/errors_en.properties +++ b/src/main/webapp/WEB-INF/i18n/errors_en.properties @@ -30,6 +30,6 @@ typeMismatch.thumbnail=Valid thumbnail format: PNG typeMismatch.java.lang.Integer={0} must be a number formatHint.Integer=Number (e.g. "5000") image.too.small=The image width must be at least 640px -image.too.big=The image size is too big +file.size.too.big=The file size is too big emoji.unicode.version=Only emojis up to Unicode version 9 WordSpace=Spaces are not allowed From 2aad690af4e704c98a274d1e81d1ddaf07c53319 Mon Sep 17 00:00:00 2001 From: Tomasz Date: Tue, 30 Aug 2022 20:49:51 +0100 Subject: [PATCH 3/3] 1077 Set 4MB size limit for images --- .../multimedia/image/ImageComponent.java | 76 +++++++++++++++++++ .../image/ImageCreateController.java | 66 ++-------------- .../multimedia/image/ImageEditController.java | 58 ++------------ .../webapp/WEB-INF/i18n/errors_en.properties | 2 +- 4 files changed, 88 insertions(+), 114 deletions(-) create mode 100644 src/main/java/ai/elimu/web/content/multimedia/image/ImageComponent.java diff --git a/src/main/java/ai/elimu/web/content/multimedia/image/ImageComponent.java b/src/main/java/ai/elimu/web/content/multimedia/image/ImageComponent.java new file mode 100644 index 000000000..698a53ab4 --- /dev/null +++ b/src/main/java/ai/elimu/web/content/multimedia/image/ImageComponent.java @@ -0,0 +1,76 @@ +package ai.elimu.web.content.multimedia.image; + +import ai.elimu.model.content.multimedia.Image; +import ai.elimu.model.v2.enums.content.ImageFormat; +import ai.elimu.util.ImageHelper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; + +import static ai.elimu.util.ImageHelper.MAX_BYTE_SIZE; + +@Component +public class ImageComponent { + + private final Logger logger = LogManager.getLogger(); + + public void validImageTypeAndSize(MultipartFile multipartFile, BindingResult result, Image image) { + try { + byte[] bytes = multipartFile.getBytes(); + if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) { + result.rejectValue("bytes", "NotNull"); + } else { + String originalFileName = multipartFile.getOriginalFilename(); + logger.info("originalFileName: " + originalFileName); + + byte[] headerBytes = Arrays.copyOfRange(bytes, 0, 6); + byte[] gifHeader87a = {71, 73, 70, 56, 55, 97}; // "GIF87a" + byte[] gifHeader89a = {71, 73, 70, 56, 57, 97}; // "GIF89a" + if (Arrays.equals(gifHeader87a, headerBytes) || Arrays.equals(gifHeader89a, headerBytes)) { + image.setImageFormat(ImageFormat.GIF); + } else if (originalFileName.toLowerCase().endsWith(".png")) { + image.setImageFormat(ImageFormat.PNG); + } else if (originalFileName.toLowerCase().endsWith(".jpg") || originalFileName.toLowerCase().endsWith(".jpeg")) { + image.setImageFormat(ImageFormat.JPG); + } else if (originalFileName.toLowerCase().endsWith(".gif")) { + image.setImageFormat(ImageFormat.GIF); + } else { + result.rejectValue("bytes", "typeMismatch"); + } + + if (image.getImageFormat() != null) { + String contentType = multipartFile.getContentType(); + logger.info("contentType: " + contentType); + image.setContentType(contentType); + + image.setBytes(bytes); + + if (image.getImageFormat() != ImageFormat.GIF) { + int width = ImageHelper.getWidth(bytes); + logger.info("width: " + width + "px"); + + if (width < ImageHelper.MINIMUM_WIDTH) { + result.rejectValue("bytes", "image.too.small"); + image.setBytes(null); + } else if (width > ImageHelper.MINIMUM_WIDTH){ + bytes = ImageHelper.scaleImage(bytes, ImageHelper.MINIMUM_WIDTH); + image.setBytes(bytes); + } + } + } + + if (bytes.length > MAX_BYTE_SIZE) { + result.rejectValue("bytes", "file.size.too.big"); + } + } + } catch (IOException e) { + logger.error(e); + } + } + +} diff --git a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java index 54deff341..7540f6980 100644 --- a/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java +++ b/src/main/java/ai/elimu/web/content/multimedia/image/ImageCreateController.java @@ -1,7 +1,7 @@ package ai.elimu.web.content.multimedia.image; import ai.elimu.dao.ImageContributionEventDao; -import java.io.IOException; + import java.util.Calendar; import java.util.HashSet; import java.util.Set; @@ -18,14 +18,12 @@ import ai.elimu.model.contributor.ImageContributionEvent; import ai.elimu.model.enums.ContentLicense; import ai.elimu.model.enums.Platform; -import ai.elimu.model.v2.enums.content.ImageFormat; import ai.elimu.model.v2.enums.content.LiteracySkill; import ai.elimu.model.v2.enums.content.NumeracySkill; import ai.elimu.util.DiscordHelper; import ai.elimu.util.ImageColorHelper; -import ai.elimu.util.ImageHelper; import ai.elimu.web.context.EnvironmentContextLoaderListener; -import java.util.Arrays; + import javax.servlet.http.HttpSession; import org.apache.logging.log4j.LogManager; import org.springframework.beans.factory.annotation.Autowired; @@ -40,8 +38,6 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor; -import static ai.elimu.util.ImageHelper.MAX_BYTE_SIZE; - @Controller @RequestMapping("/content/multimedia/image/create") public class ImageCreateController { @@ -57,6 +53,9 @@ public class ImageCreateController { @Autowired private WordDao wordDao; + @Autowired + private ImageComponent imageComponent; + @RequestMapping(method = RequestMethod.GET) public String handleRequest(Model model) { logger.info("handleRequest"); @@ -89,62 +88,9 @@ public String handleSubmit( result.rejectValue("title", "NonUnique"); } } - - try { - byte[] bytes = multipartFile.getBytes(); - if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) { - result.rejectValue("bytes", "NotNull"); - } else { - String originalFileName = multipartFile.getOriginalFilename(); - logger.info("originalFileName: " + originalFileName); - - byte[] headerBytes = Arrays.copyOfRange(bytes, 0, 6); - byte[] gifHeader87a = {71, 73, 70, 56, 55, 97}; // "GIF87a" - byte[] gifHeader89a = {71, 73, 70, 56, 57, 97}; // "GIF89a" - if (Arrays.equals(gifHeader87a, headerBytes) || Arrays.equals(gifHeader89a, headerBytes)) { - image.setImageFormat(ImageFormat.GIF); - } else if (originalFileName.toLowerCase().endsWith(".png")) { - image.setImageFormat(ImageFormat.PNG); - } else if (originalFileName.toLowerCase().endsWith(".jpg") || originalFileName.toLowerCase().endsWith(".jpeg")) { - image.setImageFormat(ImageFormat.JPG); - } else if (originalFileName.toLowerCase().endsWith(".gif")) { - image.setImageFormat(ImageFormat.GIF); - } else { - result.rejectValue("bytes", "typeMismatch"); - } - - if (image.getImageFormat() != null) { - String contentType = multipartFile.getContentType(); - logger.info("contentType: " + contentType); - image.setContentType(contentType); - image.setBytes(bytes); + imageComponent.validImageTypeAndSize(multipartFile, result, image); - if (image.getImageFormat() != ImageFormat.GIF) { - int width = ImageHelper.getWidth(bytes); - logger.info("width: " + width + "px"); - - if (width < ImageHelper.MINIMUM_WIDTH) { - result.rejectValue("bytes", "image.too.small"); - image.setBytes(null); - } else { - if (width > ImageHelper.MINIMUM_WIDTH) { - bytes = ImageHelper.scaleImage(bytes, ImageHelper.MINIMUM_WIDTH); - image.setBytes(bytes); - } - } - } - } - - if (bytes.length > MAX_BYTE_SIZE) { - result.rejectValue("bytes", "file.size.too.big"); - } - - } - } catch (IOException e) { - logger.error(e); - } - if (result.hasErrors()) { model.addAttribute("contentLicenses", ContentLicense.values()); model.addAttribute("literacySkills", LiteracySkill.values()); diff --git a/src/main/java/ai/elimu/web/content/multimedia/image/ImageEditController.java b/src/main/java/ai/elimu/web/content/multimedia/image/ImageEditController.java index c571b0c3a..1817c7e58 100644 --- a/src/main/java/ai/elimu/web/content/multimedia/image/ImageEditController.java +++ b/src/main/java/ai/elimu/web/content/multimedia/image/ImageEditController.java @@ -1,6 +1,5 @@ package ai.elimu.web.content.multimedia.image; -import java.io.IOException; import java.util.Calendar; import java.util.Iterator; import java.util.Set; @@ -26,13 +25,11 @@ import ai.elimu.model.contributor.ImageContributionEvent; import ai.elimu.model.enums.ContentLicense; import ai.elimu.model.enums.Platform; -import ai.elimu.model.v2.enums.content.ImageFormat; import ai.elimu.model.v2.enums.content.LiteracySkill; import ai.elimu.model.v2.enums.content.NumeracySkill; import ai.elimu.util.DiscordHelper; -import ai.elimu.util.ImageHelper; import ai.elimu.web.context.EnvironmentContextLoaderListener; -import java.util.Arrays; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,6 +76,9 @@ public class ImageEditController { @Autowired private AudioDao audioDao; + @Autowired + private ImageComponent imageComponent; + @RequestMapping(value = "/{id}", method = RequestMethod.GET) public String handleRequest( Model model, @@ -123,57 +123,9 @@ public String handleSubmit( result.rejectValue("title", "NonUnique"); } } - - try { - byte[] bytes = multipartFile.getBytes(); - if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) { - result.rejectValue("bytes", "NotNull"); - } else { - String originalFileName = multipartFile.getOriginalFilename(); - logger.info("originalFileName: " + originalFileName); - - byte[] headerBytes = Arrays.copyOfRange(bytes, 0, 6); - byte[] gifHeader87a = {71, 73, 70, 56, 55, 97}; // "GIF87a" - byte[] gifHeader89a = {71, 73, 70, 56, 57, 97}; // "GIF89a" - if (Arrays.equals(gifHeader87a, headerBytes) || Arrays.equals(gifHeader89a, headerBytes)) { - image.setImageFormat(ImageFormat.GIF); - } else if (originalFileName.toLowerCase().endsWith(".png")) { - image.setImageFormat(ImageFormat.PNG); - } else if (originalFileName.toLowerCase().endsWith(".jpg") || originalFileName.toLowerCase().endsWith(".jpeg")) { - image.setImageFormat(ImageFormat.JPG); - } else if (originalFileName.toLowerCase().endsWith(".gif")) { - image.setImageFormat(ImageFormat.GIF); - } else { - result.rejectValue("bytes", "typeMismatch"); - } - - if (image.getImageFormat() != null) { - String contentType = multipartFile.getContentType(); - logger.info("contentType: " + contentType); - image.setContentType(contentType); - image.setBytes(bytes); + imageComponent.validImageTypeAndSize(multipartFile, result, image); - if (image.getImageFormat() != ImageFormat.GIF) { - int width = ImageHelper.getWidth(bytes); - logger.info("width: " + width + "px"); - - if (width < ImageHelper.MINIMUM_WIDTH) { - result.rejectValue("bytes", "image.too.small"); - image.setBytes(null); - } else { - if (width > ImageHelper.MINIMUM_WIDTH) { - bytes = ImageHelper.scaleImage(bytes, ImageHelper.MINIMUM_WIDTH); - image.setBytes(bytes); - } - } - } - } - } - } catch (IOException e) { - logger.error(e); - } - if (result.hasErrors()) { model.addAttribute("image", image); model.addAttribute("contentLicenses", ContentLicense.values()); diff --git a/src/main/webapp/WEB-INF/i18n/errors_en.properties b/src/main/webapp/WEB-INF/i18n/errors_en.properties index 685db41c5..85949b955 100644 --- a/src/main/webapp/WEB-INF/i18n/errors_en.properties +++ b/src/main/webapp/WEB-INF/i18n/errors_en.properties @@ -30,6 +30,6 @@ typeMismatch.thumbnail=Valid thumbnail format: PNG typeMismatch.java.lang.Integer={0} must be a number formatHint.Integer=Number (e.g. "5000") image.too.small=The image width must be at least 640px -file.size.too.big=The file size is too big +file.size.too.big=The file size is too big (max 4MB) emoji.unicode.version=Only emojis up to Unicode version 9 WordSpace=Spaces are not allowed