diff --git a/src/main/java/org/qortal/arbitrary/misc/Service.java b/src/main/java/org/qortal/arbitrary/misc/Service.java index 5dd8d94e..dc2deaeb 100644 --- a/src/main/java/org/qortal/arbitrary/misc/Service.java +++ b/src/main/java/org/qortal/arbitrary/misc/Service.java @@ -10,9 +10,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import static java.util.Arrays.stream; import static java.util.stream.Collectors.toMap; @@ -20,6 +18,31 @@ import static java.util.stream.Collectors.toMap; public enum Service { AUTO_UPDATE(1, false, null, null), ARBITRARY_DATA(100, false, null, null), + QCHAT_ATTACHMENT(120, true, 1024*1024L, null) { + @Override + public ValidationResult validate(Path path) { + // Custom validation function to require a single file, with a whitelisted extension + int fileCount = 0; + File[] files = path.toFile().listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + return ValidationResult.DIRECTORIES_NOT_ALLOWED; + } + final String extension = FilenameUtils.getExtension(file.getName()).toLowerCase(); + final List allowedExtensions = Arrays.asList("zip", "pdf", "txt", "odt", "ods", "doc", "docx", "xls", "xlsx", "ppt", "pptx"); + if (extension == null || !allowedExtensions.contains(extension)) { + return ValidationResult.INVALID_FILE_EXTENSION; + } + fileCount++; + } + } + if (fileCount != 1) { + return ValidationResult.INVALID_FILE_COUNT; + } + return ValidationResult.OK; + } + }, WEBSITE(200, true, null, null) { @Override public ValidationResult validate(Path path) { @@ -143,7 +166,8 @@ public enum Service { MISSING_INDEX_FILE(4), DIRECTORIES_NOT_ALLOWED(5), INVALID_FILE_EXTENSION(6), - MISSING_DATA(7); + MISSING_DATA(7), + INVALID_FILE_COUNT(8); public final int value; diff --git a/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java b/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java index e6a51776..f7738c45 100644 --- a/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java +++ b/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java @@ -175,4 +175,93 @@ public class ArbitraryServiceTests extends Common { assertEquals(ValidationResult.INVALID_FILE_EXTENSION, service.validate(path)); } -} + @Test + public void testValidateQChatAttachment() throws IOException { + // Generate some random data + byte[] data = new byte[1024]; + new Random().nextBytes(data); + + // Write the data to several files in a temp path + Path path = Files.createTempDirectory("testValidateQChatAttachment"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "document.pdf"), data, StandardOpenOption.CREATE); + + Service service = Service.QCHAT_ATTACHMENT; + assertTrue(service.isValidationRequired()); + + // There is an index file in the root + assertEquals(ValidationResult.OK, service.validate(path)); + } + + @Test + public void testValidateInvalidQChatAttachmentFileExtension() throws IOException { + // Generate some random data + byte[] data = new byte[1024]; + new Random().nextBytes(data); + + // Write the data to several files in a temp path + Path path = Files.createTempDirectory("testValidateInvalidQChatAttachmentFileExtension"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "application.exe"), data, StandardOpenOption.CREATE); + + Service service = Service.QCHAT_ATTACHMENT; + assertTrue(service.isValidationRequired()); + + // There is an index file in the root + assertEquals(ValidationResult.INVALID_FILE_EXTENSION, service.validate(path)); + } + + @Test + public void testValidateEmptyQChatAttachment() throws IOException { + Path path = Files.createTempDirectory("testValidateEmptyQChatAttachment"); + + Service service = Service.QCHAT_ATTACHMENT; + assertTrue(service.isValidationRequired()); + + // There is an index file in the root + assertEquals(ValidationResult.INVALID_FILE_COUNT, service.validate(path)); + } + + @Test + public void testValidateMultiLayerQChatAttachment() throws IOException { + // Generate some random data + byte[] data = new byte[1024]; + new Random().nextBytes(data); + + // Write the data to several files in a temp path + Path path = Files.createTempDirectory("testValidateMultiLayerQChatAttachment"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "file1.txt"), data, StandardOpenOption.CREATE); + + Path subdirectory = Paths.get(path.toString(), "subdirectory"); + Files.createDirectories(subdirectory); + Files.write(Paths.get(subdirectory.toString(), "file2.txt"), data, StandardOpenOption.CREATE); + Files.write(Paths.get(subdirectory.toString(), "file3.txt"), data, StandardOpenOption.CREATE); + + Service service = Service.QCHAT_ATTACHMENT; + assertTrue(service.isValidationRequired()); + + // There is an index file in the root + assertEquals(ValidationResult.DIRECTORIES_NOT_ALLOWED, service.validate(path)); + } + + @Test + public void testValidateMultiFileQChatAttachment() throws IOException { + // Generate some random data + byte[] data = new byte[1024]; + new Random().nextBytes(data); + + // Write the data to several files in a temp path + Path path = Files.createTempDirectory("testValidateMultiFileQChatAttachment"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "file1.txt"), data, StandardOpenOption.CREATE); + Files.write(Paths.get(path.toString(), "file2.txt"), data, StandardOpenOption.CREATE); + + Service service = Service.QCHAT_ATTACHMENT; + assertTrue(service.isValidationRequired()); + + // There is an index file in the root + assertEquals(ValidationResult.INVALID_FILE_COUNT, service.validate(path)); + } + +} \ No newline at end of file