From 57e82b62a1ac85886630a530f09a027ed2151d1e Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 5 Dec 2021 13:03:22 +0000 Subject: [PATCH] Increased the capabilities of the service validation functions. --- .../qortal/arbitrary/ArbitraryDataReader.java | 6 +- .../qortal/arbitrary/ArbitraryDataWriter.java | 6 +- .../org/qortal/arbitrary/misc/Service.java | 18 ++++- .../test/arbitrary/ArbitraryServiceTests.java | 78 +++++++++++++++---- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java index b45390fe..bc4c8d9a 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java @@ -444,11 +444,7 @@ public class ArbitraryDataReader { private void validate() throws IOException, DataException { if (this.service.isValidationRequired()) { - - byte[] data = FilesystemUtils.getSingleFileContents(this.filePath); - long size = FilesystemUtils.getDirectorySize(this.filePath); - - Service.ValidationResult result = this.service.validate(data, size); + Service.ValidationResult result = this.service.validate(this.filePath); if (result != Service.ValidationResult.OK) { throw new DataException(String.format("Validation of %s failed: %s", this.service, result.toString())); } diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java index 664bc11d..354f1605 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataWriter.java @@ -105,11 +105,7 @@ public class ArbitraryDataWriter { private void validateService() throws IOException, DataException { if (this.service.isValidationRequired()) { - - byte[] data = FilesystemUtils.getSingleFileContents(this.filePath); - long size = FilesystemUtils.getDirectorySize(this.filePath); - - Service.ValidationResult result = this.service.validate(data, size); + Service.ValidationResult result = this.service.validate(this.filePath); if (result != Service.ValidationResult.OK) { throw new DataException(String.format("Validation of %s failed: %s", this.service, result.toString())); } diff --git a/src/main/java/org/qortal/arbitrary/misc/Service.java b/src/main/java/org/qortal/arbitrary/misc/Service.java index ca99ca2c..337739d3 100644 --- a/src/main/java/org/qortal/arbitrary/misc/Service.java +++ b/src/main/java/org/qortal/arbitrary/misc/Service.java @@ -1,8 +1,13 @@ package org.qortal.arbitrary.misc; import org.json.JSONObject; +import org.qortal.arbitrary.ArbitraryDataRenderer; import org.qortal.transaction.Transaction; +import org.qortal.utils.FilesystemUtils; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -44,20 +49,26 @@ public enum Service { this.requiredKeys = requiredKeys; } - public ValidationResult validate(byte[] data, long size) { + public ValidationResult validate(Path path) throws IOException { if (!this.isValidationRequired()) { return ValidationResult.OK; } + byte[] data = FilesystemUtils.getSingleFileContents(path); + long size = FilesystemUtils.getDirectorySize(path); + // Validate max size if needed if (this.maxSize != null) { - if (size > this.maxSize || data.length > this.maxSize) { + if (size > this.maxSize) { return ValidationResult.EXCEEDS_SIZE_LIMIT; } } // Validate required keys if needed if (this.requiredKeys != null) { + if (data == null) { + return ValidationResult.MISSING_KEYS; + } JSONObject json = Service.toJsonObject(data); for (String key : this.requiredKeys) { if (!json.has(key)) { @@ -86,7 +97,8 @@ public enum Service { public enum ValidationResult { OK(1), MISSING_KEYS(2), - EXCEEDS_SIZE_LIMIT(3); + EXCEEDS_SIZE_LIMIT(3), + MISSING_INDEX_FILE(4); 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 1f970f40..ac77a0f0 100644 --- a/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java +++ b/src/test/java/org/qortal/test/arbitrary/ArbitraryServiceTests.java @@ -7,6 +7,11 @@ import org.qortal.arbitrary.misc.Service.ValidationResult; import org.qortal.repository.DataException; import org.qortal.test.common.Common; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.Random; import static org.junit.Assert.*; @@ -19,49 +24,94 @@ public class ArbitraryServiceTests extends Common { } @Test - public void testDefaultValidation() { - // We don't validate websites yet, but we still want to test the default validation method + public void testDefaultValidation() throws IOException { + // We don't validate the ARBITRARY_DATA service specifically, so we can use it to test the default validation method byte[] data = new byte[1024]; new Random().nextBytes(data); - Service service = Service.WEBSITE; + // Write to temp path + Path path = Files.createTempFile("testDefaultValidation", null); + path.toFile().deleteOnExit(); + Files.write(path, data, StandardOpenOption.CREATE); + + Service service = Service.ARBITRARY_DATA; assertFalse(service.isValidationRequired()); // Test validation anyway to ensure that no exception is thrown - assertEquals(ValidationResult.OK, service.validate(data, data.length)); + assertEquals(ValidationResult.OK, service.validate(path)); } @Test - public void testValidQortalMetadata() { + public void testValidQortalMetadata() throws IOException { // Metadata is to describe an arbitrary resource (title, description, tags, etc) String dataString = "{\"title\":\"Test Title\", \"description\":\"Test description\", \"tags\":[\"test\"]}"; - byte[] data = dataString.getBytes(); + + // Write to temp path + Path path = Files.createTempFile("testValidQortalMetadata", null); + path.toFile().deleteOnExit(); + Files.write(path, dataString.getBytes(), StandardOpenOption.CREATE); Service service = Service.QORTAL_METADATA; assertTrue(service.isValidationRequired()); - assertEquals(ValidationResult.OK, service.validate(data, data.length)); + assertEquals(ValidationResult.OK, service.validate(path)); } @Test - public void testQortalMetadataMissingKeys() { + public void testQortalMetadataMissingKeys() throws IOException { // Metadata is to describe an arbitrary resource (title, description, tags, etc) String dataString = "{\"description\":\"Test description\", \"tags\":[\"test\"]}"; - byte[] data = dataString.getBytes(); + + // Write to temp path + Path path = Files.createTempFile("testQortalMetadataMissingKeys", null); + path.toFile().deleteOnExit(); + Files.write(path, dataString.getBytes(), StandardOpenOption.CREATE); Service service = Service.QORTAL_METADATA; assertTrue(service.isValidationRequired()); - assertEquals(ValidationResult.MISSING_KEYS, service.validate(data, data.length)); + assertEquals(ValidationResult.MISSING_KEYS, service.validate(path)); } @Test - public void testQortalMetadataTooLarge() { + public void testQortalMetadataTooLarge() throws IOException { // Metadata is to describe an arbitrary resource (title, description, tags, etc) String dataString = "{\"title\":\"Test Title\", \"description\":\"Test description\", \"tags\":[\"test\"]}"; - byte[] data = dataString.getBytes(); - long totalResourceSize = 11*1024L; // Larger than allowed 10kiB + + // Generate some large data to go along with it + int largeDataSize = 11*1024; // Larger than allowed 10kiB + byte[] largeData = new byte[largeDataSize]; + new Random().nextBytes(largeData); + + // Write to temp path + Path path = Files.createTempDirectory("testQortalMetadataTooLarge"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "data"), dataString.getBytes(), StandardOpenOption.CREATE); + Files.write(Paths.get(path.toString(), "large_data"), largeData, StandardOpenOption.CREATE); Service service = Service.QORTAL_METADATA; assertTrue(service.isValidationRequired()); - assertEquals(ValidationResult.EXCEEDS_SIZE_LIMIT, service.validate(data, totalResourceSize)); + assertEquals(ValidationResult.EXCEEDS_SIZE_LIMIT, service.validate(path)); + } + + @Test + public void testMultipleFileMetadata() throws IOException { + // Metadata is to describe an arbitrary resource (title, description, tags, etc) + String dataString = "{\"title\":\"Test Title\", \"description\":\"Test description\", \"tags\":[\"test\"]}"; + + // Generate some large data to go along with it + int otherDataSize = 1024; // Smaller than 10kiB limit + byte[] otherData = new byte[otherDataSize]; + new Random().nextBytes(otherData); + + // Write to temp path + Path path = Files.createTempDirectory("testMultipleFileMetadata"); + path.toFile().deleteOnExit(); + Files.write(Paths.get(path.toString(), "data"), dataString.getBytes(), StandardOpenOption.CREATE); + Files.write(Paths.get(path.toString(), "other_data"), otherData, StandardOpenOption.CREATE); + + Service service = Service.QORTAL_METADATA; + assertTrue(service.isValidationRequired()); + + // There are multiple files, so we don't know which one to parse as JSON + assertEquals(ValidationResult.MISSING_KEYS, service.validate(path)); } }