diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/ValidationMessageCodes.java b/goofy-server/src/main/java/de/itvsh/goofy/common/ValidationMessageCodes.java index 58616c47f83fd0416358200096c0479e7b050cef..e48ce06cd988e3a4d0f7038a6f9159e3c5418aa3 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/ValidationMessageCodes.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/ValidationMessageCodes.java @@ -11,4 +11,5 @@ public class ValidationMessageCodes { public static final String FIELD_SIZE = FIELD_PREFIX + "size"; public static final String FIELD_DATE_PAST = FIELD_PREFIX + "date_past"; public static final String FIELD_INVALID = FIELD_PREFIX + "invalid"; + public static final String FIELD_FILE_SIZE_EXCEEDED = FIELD_PREFIX + "file_size_exceeded"; } \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileController.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileController.java index 9766d370ea8eb4226792da064f58fc6482a5230c..cf573e9ad548240e4c7bda7f47431f2d85bbbed6 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileController.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileController.java @@ -76,8 +76,10 @@ public class BinaryFileController { return UploadBinaryFileRequest.builder() .vorgangId(vorgangId) .field(field) - .ozgFile(buildOzgFile(file)) .uploadStream(getInputStream(file)) + .name(file.getOriginalFilename()) + .contentType(file.getContentType()) + .size(file.getSize()) .build(); } @@ -89,14 +91,6 @@ public class BinaryFileController { } } - OzgFile buildOzgFile(MultipartFile file) { - return OzgFile.builder() - .name(file.getOriginalFilename()) - .contentType(file.getContentType()) - .size(file.getSize()) - .build(); - } - public CollectionModel<EntityModel<OzgFile>> getFiles(List<FileId> fileIds) { var files = service.getFiles(mapToFileId(fileIds)).toList(); diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileMaxSizeConstraint.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileMaxSizeConstraint.java new file mode 100644 index 0000000000000000000000000000000000000000..6d6cebd3deebbfa22dcc7e77c8f07bddee2a7f1b --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileMaxSizeConstraint.java @@ -0,0 +1,25 @@ +package de.itvsh.goofy.common.binaryfile; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import de.itvsh.goofy.common.ValidationMessageCodes; + +@Constraint(validatedBy = UploadBinaryFileSizeValidator.class) +@Target({ TYPE }) +@Retention(RUNTIME) +@Documented +public @interface BinaryFileMaxSizeConstraint { + String message() default ValidationMessageCodes.FIELD_FILE_SIZE_EXCEEDED; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileProperties.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..4d862539d7b93df67c23730e6e7ac97581baa57d --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileProperties.java @@ -0,0 +1,21 @@ +package de.itvsh.goofy.common.binaryfile; + +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Configuration +@ConfigurationProperties(BinaryFileProperties.PREFIX) +class BinaryFileProperties { + + static final String PREFIX = "goofy.upload"; + + private Map<String, Integer> maxFileSize; + +} \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java index 276becbcddaf33035f9c405de01c9c90089da96d..ecce387c15ca74e852306144f641acae15a3ca57 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java @@ -115,9 +115,9 @@ class BinaryFileRemoteService { .setContext(contextService.createCallContext()) .setVorgangId(uploadBinaryFileRequest.getVorgangId()) .setField(uploadBinaryFileRequest.getField()) - .setContentType(uploadBinaryFileRequest.getOzgFile().getContentType()) - .setSize(uploadBinaryFileRequest.getOzgFile().getSize()) - .setFileName(uploadBinaryFileRequest.getOzgFile().getName())) + .setContentType(uploadBinaryFileRequest.getContentType()) + .setSize(uploadBinaryFileRequest.getSize()) + .setFileName(uploadBinaryFileRequest.getName())) .build(); } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileService.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileService.java index df884133481f057c29b0902bbf28777f76977567..33f67ca1c7072c5caa02a0b1b12e2c623ac2f9dc 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileService.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileService.java @@ -5,13 +5,17 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; +import javax.validation.Valid; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; import de.itvsh.goofy.common.file.OzgFile; import de.itvsh.goofy.common.file.OzgFileData; @Service +@Validated class BinaryFileService { @Autowired @@ -22,7 +26,7 @@ class BinaryFileService { return remoteService.uploadFile(vorgangId, fieldName, file); } - public CompletableFuture<FileId> uploadFile(UploadBinaryFileRequest uploadBinaryFileRequest) { + public CompletableFuture<FileId> uploadFile(@Valid UploadBinaryFileRequest uploadBinaryFileRequest) { return remoteService.uploadFile(uploadBinaryFileRequest); } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileRequest.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileRequest.java index 165aa4682868f7d42179bd38f7e3b97e8ad8e937..9c6eeddfcac381f7e8a38c97497102357fdf078e 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileRequest.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileRequest.java @@ -2,16 +2,22 @@ package de.itvsh.goofy.common.binaryfile; import java.io.InputStream; -import de.itvsh.goofy.common.file.OzgFile; +import org.springframework.validation.annotation.Validated; + import lombok.Builder; import lombok.Getter; @Getter @Builder +@Validated +@BinaryFileMaxSizeConstraint class UploadBinaryFileRequest { private String vorgangId; private String field; - private OzgFile ozgFile; + + private String name; + private String contentType; + private long size; private InputStream uploadStream; } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidator.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..32555e82962964f4494c2ea641036e858c3320ae --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidator.java @@ -0,0 +1,25 @@ +package de.itvsh.goofy.common.binaryfile; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.springframework.beans.factory.annotation.Autowired; + +class UploadBinaryFileSizeValidator implements ConstraintValidator<BinaryFileMaxSizeConstraint, UploadBinaryFileRequest> { + + @Autowired + private BinaryFileProperties binaryFileProperties; + + @Override + public boolean isValid(UploadBinaryFileRequest uploadRequest, ConstraintValidatorContext context) { + return uploadRequest.getSize() <= toMegabyte(getMaxValidSize(uploadRequest.getField())); + } + + private long toMegabyte(Integer byteValue) { + return byteValue.longValue() * 1024 * 1024; + } + + private Integer getMaxValidSize(String field) { + return binaryFileProperties.getMaxFileSize().get(field); + } +} \ No newline at end of file diff --git a/goofy-server/src/main/resources/application.yml b/goofy-server/src/main/resources/application.yml index d940267afa26501359680abba341e55c2d09608f..e1d85b5e7b035f3be4afb33873828c87a272c4dd 100644 --- a/goofy-server/src/main/resources/application.yml +++ b/goofy-server/src/main/resources/application.yml @@ -14,6 +14,10 @@ spring: jackson: deserialization: 'ADJUST_DATES_TO_CONTEXT_TIME_ZONE': false + servlet: + multipart: + max-file-size: 40MB + max-request-size: 40MB server: http2: @@ -48,6 +52,9 @@ goofy: api: user: goofyApiUser password: + upload: + maxFileSize: + postfachNachrichtAttachment: 40 keycloak: auth-server-url: http://localhost:8088/auth diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileControllerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileControllerTest.java index 396be3d268bb2ac3c4f0e49ebbd285ded43b4869..f09961d40191ece6f42b5abaadce5e25c77c2eaf 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileControllerTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileControllerTest.java @@ -131,7 +131,7 @@ class BinaryFileControllerTest { } @Nested - class TestBuildBinaryFileUpload { + class TestBuildBinaryFileUploadRequest { @Test void shouldContainsVorgangId() { @@ -148,10 +148,24 @@ class BinaryFileControllerTest { } @Test - void shouldContainsOzgFile() { + void shouldContainsSize() { + var result = buildBinaryFileUploadRequest(); + + assertThat(result.getSize()).isEqualTo(OzgFileTestFactory.SIZE); + } + + @Test + void shouldContainsName() { + var result = buildBinaryFileUploadRequest(); + + assertThat(result.getName()).isEqualTo(OzgFileTestFactory.NAME); + } + + @Test + void shouldContainsContentType() { var result = buildBinaryFileUploadRequest(); - assertThat(result.getOzgFile()).usingRecursiveComparison().ignoringFields("id").isEqualTo(UploadBinaryFileTestFactory.OZG_FILE); + assertThat(result.getContentType()).isEqualTo(OzgFileTestFactory.CONTENT_TYPE); } @Test @@ -189,35 +203,6 @@ class BinaryFileControllerTest { } } - @Nested - class TestBuildOzgFile { - - @Test - void shouldContainsOriginalFilename() { - var ozgFile = callBuildOzgFile(); - - assertThat(ozgFile.getName()).isEqualTo(BinaryFileTestFactory.NAME); - } - - @Test - void shouldContainsContentType() { - var ozgFile = callBuildOzgFile(); - - assertThat(ozgFile.getContentType()).isEqualTo(BinaryFileTestFactory.CONTENT_TYPE); - } - - @Test - void shouldContainsSize() { - var ozgFile = callBuildOzgFile(); - - assertThat(ozgFile.getSize()).isEqualTo(BinaryFileTestFactory.SIZE); - } - - private OzgFile callBuildOzgFile() { - return controller.buildOzgFile(BinaryFileTestFactory.TEST_FILE); - } - } - @Nested class TestGetFile { diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidatorTest.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0288f9a48ea3fb78af77e5679538fa3915c1667f --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileSizeValidatorTest.java @@ -0,0 +1,50 @@ +package de.itvsh.goofy.common.binaryfile; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Map; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +class UploadBinaryFileSizeValidatorTest { + + @InjectMocks + private UploadBinaryFileSizeValidator validator = new UploadBinaryFileSizeValidator(); + @Mock + private BinaryFileProperties properties; + + @Nested + class TestIsValid { + + @Test + void shouldCallProperties() { + when(properties.getMaxFileSize()).thenReturn(Map.of(UploadBinaryFileTestFactory.FIELD, 1)); + + validator.isValid(UploadBinaryFileTestFactory.create(), null); + + verify(properties).getMaxFileSize(); + } + + @Test + void shouldReturnFalse() { + when(properties.getMaxFileSize()).thenReturn(Map.of(UploadBinaryFileTestFactory.FIELD, 9)); + + var isValid = validator.isValid(UploadBinaryFileTestFactory.createBuilder().size(10 * 1024 * 1024).build(), null); + + assertThat(isValid).isFalse(); + } + + @Test + void shouldReturnTrue() { + when(properties.getMaxFileSize()).thenReturn(Map.of(UploadBinaryFileTestFactory.FIELD, 10)); + + var isValid = validator.isValid(UploadBinaryFileTestFactory.createBuilder().size(10 * 1024 * 1024).build(), null); + + assertThat(isValid).isTrue(); + } + } +} diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileTestFactory.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileTestFactory.java index 28428545364339b48d166c757d6f8e881d0662d6..4a4262bae0fa20eefc52c6d529a0ad2194022c15 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileTestFactory.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/UploadBinaryFileTestFactory.java @@ -1,16 +1,15 @@ package de.itvsh.goofy.common.binaryfile; +import static de.itvsh.goofy.common.file.OzgFileTestFactory.*; + import java.io.InputStream; -import de.itvsh.goofy.common.file.OzgFile; -import de.itvsh.goofy.common.file.OzgFileTestFactory; import de.itvsh.goofy.vorgang.VorgangHeaderTestFactory; public class UploadBinaryFileTestFactory { static final String VORGANG_ID = VorgangHeaderTestFactory.ID; static final String FIELD = BinaryFileTestFactory.FIELD; - static final OzgFile OZG_FILE = OzgFileTestFactory.create(); static final InputStream UPLOAD_STREAM = BinaryFileTestFactory.STREAM; public static UploadBinaryFileRequest create() { @@ -19,9 +18,11 @@ public class UploadBinaryFileTestFactory { public static UploadBinaryFileRequest.UploadBinaryFileRequestBuilder createBuilder() { return UploadBinaryFileRequest.builder() + .name(NAME) .vorgangId(VORGANG_ID) .field(FIELD) - .ozgFile(OZG_FILE) + .size(SIZE) + .contentType(CONTENT_TYPE) .uploadStream(UPLOAD_STREAM); } -} +} \ No newline at end of file